/* Copyright (c) 1990-2025, Jsoftware Inc.  All rights reserved.           */
/* Licensed use only. Any other use is in violation of copyright.          */
/*                                                                         */
/* Type Definitions                                                        */

#define U unsigned

#if (SYS & SYS_UNIX)
#define _stdcall      
#endif

#ifdef _WIN32
#define CDPROC
#elif defined(__GNUC__)
#define CDPROC __attribute__ ((visibility ("default")))
#else
#define CDPROC
#endif

#if SY_64
typedef long long          I;
typedef long long          SB;
typedef unsigned long long UI;
typedef unsigned long long UIL;   /* for typecast 8 byte double */
typedef long long          IL;
//NANFLAG is used internally as a special value that is not generated by any normal operations.  It is represented in integer form,
// and is used only when SZI==SZD
#define NANFLAG 0x7ff28da91LL  // signaling NaN with a particular value

#else
typedef int                I;
typedef int                SB;
typedef unsigned int       UI;
typedef unsigned long long UIL;
typedef long long          IL;
#endif
typedef unsigned long long UI8;
#if SY_WIN32
typedef __int64 I8;
#else
typedef long long I8;
#endif

typedef unsigned short FLOAT16;  // top 16 bits of a floating-point value, used to save space for approximate values.  Goes up to 1e38, more than _Float16
#define FLOAT16TOFLOAT(f) (*(float*)&(UI4){(f)<<16})
#define FLOATTOFLOAT16(f) ((FLOAT16)(*(UI4*)&(float){(f)}>>16))
#define FLOAT16TOI(f) (I)FLOAT16TOFLOAT(f)
#define ITOFLOAT16(f) FLOATTOFLOAT16(f)

typedef char               B;
typedef unsigned char      C;
typedef signed char        I1;
typedef char*              Ptr;
typedef short              S;
typedef short              C2;
typedef unsigned int       C4;
typedef unsigned char      UC;
typedef unsigned short     US;
typedef unsigned short     UI2;
typedef unsigned int       UINT;
typedef short              I2;
typedef int                I4;
typedef unsigned int       UI4;
typedef double             D;
typedef float              DS;
typedef FILE*              F;

typedef long double        LD;

// This is the main structure for J entities
typedef UC                 RANKT;
#define RANKTX             8   // # bits in a RANKT
#define LGRANKTX           3  // lg2(RANKTX)
#define RANKTMSK           (((I)1<<RANKTX)-1)
typedef US                 RANK2T;  // 2 ranks, (l<<8)|r
typedef UI4                RANK4T;  // 4 ranks
#define RANK2TX            16   // # bits in a RANK2T
#define LGRANK2TX          4  // lg2(RANK2TX)
#define RANK2TMSK           0xFFFFU
#define LGRMAX             6  // lg2(RMAX+1)
#define RMAX               (((I)1<<LGRMAX)-1)   // max rank, leaving 2 bits for flags
#define R2MAX              ((RMAX<<RANKTX)+RMAX)  // max value of a RANK2T

typedef I                  FLAGT;
typedef I4                LX;  // index of an L block in SYMORIGIN

typedef struct AD AD;
typedef AD *A;

typedef struct {A a,t;}TA;
typedef A                (*AF)();
typedef UI               (*UF)();
typedef I                (*VF)();  // action verb for atomic dyad
typedef I                (*VA1F)();  // action verb for atomic monad
typedef I                (*VARPSF)();  // action verb for atomic reduce/prefix/suffix routine
typedef B                (*CMP)();    /* comparison function in sort     */
typedef A                  X;
typedef struct {X n,d;}    Q;
typedef struct {D re,im;}  Z;
typedef struct {D hi,lo;}  E;  // bigendian for sort purposes
typedef union {D d;UINT i[2];UI ui;} DI;

#if (SYS & SYS_PC+SYS_MACINTOSH)        /* for use by the session manager  */
typedef S SI;
#else
typedef I SI;
#endif


// *************************Flag bits in the low-order part of jt - used only if the function being called understands inplacing ************************

#define JTINPLACEWX     0   // turn this on in jt to indicate that w can be inplaced
#define JTINPLACEW      (((I)1)<<JTINPLACEWX)
#define JTINPLACEAX     1   // turn this on in jt to indicate that a can be inplaced.  Must be 1+JTINPLACEWX
#define JTINPLACEA      (((I)1)<<JTINPLACEAX)

// Flags in hook/fork and rank loops, therefore destroyed for any verb using F?RANK
// Bit 3 in JT is unused, to allow for carry from PROP to WILLOPEN
// Next flag must match result.h and VF2 flags, and must be above ZZFLAGBOXATOP
#define JTWILLBEOPENEDX 4   // result of this exec will be opened immediately, so it can contain virtual references to an input to the current verb
     // Note: this flag MUST NOT equal BOX, or BOX<<1, or 1 or 2
#define JTWILLBEOPENED  (((I)1)<<JTWILLBEOPENEDX)
#define JTRETRYX        6  // in va2, this bit is set to indicate that the current execution is a retry
#define JTRETRY         (((I)1)<<JTRETRYX)
// Next flag must match result.h and VF2 flags, and must be above ZZFLAGBOXATOP
#define JTCOUNTITEMSX   7   // result of this exec will be go into ;, so an item count in m would be helpful
#define JTCOUNTITEMS    (((I)1)<<JTCOUNTITEMSX)

// following bit used as arg to parse
#define JTFROMEXECX    0   // parser call from ". - makes some features unavailable
#define JTFROMEXEC      (((I)1)<<JTFROMEXECX)
// following bit used as arg to jtfolk
#define JTFOLKNOHFNX    2   // set to get the generic fork that does not expect the hfn in localuse
#define JTFOLKNOHFN      (((I)1)<<JTFOLKNOHFNX)
// following bit used as arg to jtope
#define JTNOFILLX    2   // says raise an error if fill was used when opening the argument
#define JTNOFILL      (((I)1)<<JTNOFILLX)
// following bit used as arg to jtover
#define JTALLOWRETARGX    2   // allow jtover to return an argument if empty appended to it
#define JTALLOWRETARG      (((I)1)<<JTALLOWRETARGX)
// following bit used as arg to jtmatch
#define JTNOTMATCHX    2   // match should return -.@-:
#define JTNOTMATCH      (((I)1)<<JTNOTMATCHX)
// following bits is used inside/input to jtlrep only
#define JTNORESETERRX   0   // 
#define JTNORESETERR        (((I)1)<<JTNORESETERRX)
#define JTPARENSX       1   // create fully parenthesized output
#define JTPARENS        (((I)1)<<JTPARENSX)
// following are input to jtlrep and jtunparsem
#define JTEXPVALENCEOFFX 2   // bits 2-3, bit turn on to suppress display of valence
#define JTEXPVALENCEOFF  (((I)3)<<JTEXPVALENCEOFFX)
#define JTEXPVALENCEOFFM  (((I)1)<<JTEXPVALENCEOFFX)  // monad flag
#define JTEXPVALENCEOFFD  (((I)2)<<JTEXPVALENCEOFFX)  // dyad flag
// following is passed from ^:_. to u^:v which is the only thing ^:_. can call
#define JTDOWHILEX 2   // return A(1) if v returns false
#define JTDOWHILE  (((I)1)<<JTDOWHILEX)


// following bits are passed into jpr/jpr1/immex/immea/showerr/wri; bit 4 also to jtlrep
#define JTPRTYO         7  // mask for output class, see MTYO*
#define JTPRNOSTDOUTX   3   // set to suppress typing sentence result on stdout (as in scripts)
#define JTPRNOSTDOUT    (((I)1)<<JTPRNOSTDOUTX)
#define JTPRFORSCREENX  4   // set if the typeout is going to screen (rather than to 5!:5)
#define JTPRFORSCREEN    (((I)1)<<JTPRFORSCREENX)
// following bit is used in sort/grade to indicate sort direction
#define JTDESCENDX      2   // direction of sort
#define JTDESCEND       (((I)1)<<JTDESCENDX)
// following 2 bits used as input/return for jtsymbis only
#define JTFINALASGNX    0   // turn this on in jt to indicate that the assignment is final and does not have to worry about protecting the input value
#define JTFINALASGN     (((I)1)<<JTFINALASGNX)
#define JTASGNWASLOCALX  1   // in return from symbis, set if assignment was to local symbol table
#define JTASGNWASLOCAL     (((I)1)<<JTASGNWASLOCALX)
// following bits are used in thorn for boxes
#define JTTHORNYX       2  // 0, 1, or 2 for min/center/max for positioning of formatted data in boxes: horiz
#define JTTHORNY    (((I)3)<<JTTHORNYX)
#define JTTHORNXX       4  // 0, 1, or 2 for min/center/max for positioning of formatted data in boxes: vert
#define JTTHORNX    (((I)3)<<JTTHORNXX)

// following bit is used in the call to jtxdefn/unquote to indicate the execution is of a modifier
// This bit is set in ALL calls to modifiers, in case they are named
// ****** This bit should not be used for any other purpose ******
// ****** this should be the highest flag bit, because it & above bits are preserved for the call
#define JTXDEFMODIFIERX      8   // the executed entity is an adverb or conjunction
#define JTXDEFMODIFIER       (((I)1)<<JTXDEFMODIFIERX)

#define JTFLAGMSK       511  // mask big enough to cover all defined flags
#define JTALIGNBDY      MAX(8192,(MAXTHREADSRND<<LGTHREADBLKSIZE))  // jt is aligned on this boundary - all lower bits are 0 (the value is the size of an SDRAM page, to avoid row precharges while accessing jt)

struct AD {
 union {
  I k;  // 0
  A chain;   // used when block is on free chain
  A globalst;  // for local symbol tables (SYMB types), AK points to the active global symbol table, i. e. jt->global, when that table is active
  A *locpath;  // for non-local SYMB (named and numeric), AK points to the path, which is the end of a list of addresses of SYMBs
             // LOCPATH is tricky because it is used during name lookup but can be modified all over, and can be assigned even when no thread is executing the
             // locale, which means that the locale can be deleted while the path is being changed.  We make these rules: (1) use atomic_exchange to modify LOCPATH;
             // (2) if you exchange out a nonzero, you have to free it; (3) you can replace a nonzero with another nonzero only under system lock, and if you
             // are changing the block address (i. e. not extending) you must take a system lock before freeing
  A global;      // for user JOB blocks, points to jt->global for the job
 } kchain;
 FLAGT flag; // 1
 union { // 2
  I m;  // Multi-use field. (1) For NJA/SMM blocks, size of allocation. (2) in syncos, a credential to allow pthread calls
        // (3) for SYMB tables for explicit definitions (i. e. local SYMB tables), the address of the calling symbol table;
        // (4) for the block holding the amend offsets in x u} y, the number of axes of y that are built into the indexes in u
        // (5) in the return from wordil, holds the number of words if any final NB. is discarded; (6) in the result of indexofsub when called for FORKEY, contains the
        // number of partitions found; (7) in the self block for y L: n and u S: n, the address of the fs block for u; (8) in the call to jtisf (multiple assignment), holds the
        // address of the symbol table being assigned to (9) in the y block internal to pv.c, used for flags (10) in all tables that use extendunderlock, the number of valid entries in the table (AN gives the allocation)
        // (11) in file-lock list and file-number list, the # valid files (12) if AFUNIFORMITEMS is set, the total# items in all boxes (13) in JT(jt,stnum), the numbered-locale table, the number of locales outstanding
        // (14) in the filenames pointed to by fopafl, the file handle for the open file (15) for fret block passed from /.. into ;., the address of the original a arg to /..
        // (16) in permuted W block passed from /. to ;., pointer to information on where frets are in a (17) in all NAME blocks for local symbol tables, lookaside pointer to value if any (QCSYMVAL semantics)
        // (18) in a DIC block, used as a lock by user functions
  A back; // For VIRTUAL blocks, points to backing block
  A jobpyx;    // for user JOB blocks, points to the pyx or (for task with locales) pyx list
  A *zaploc;  // For all blocks allocated by GA, AM initially holds a pointer to the place in the tpop stack (or hijacked tpop stack) that points back to the allocated block.  This value is guaranteed
        // to remain valid as long as the block is nonvirtual inplaceable and might possibly return as a result to the parser or result assembly  (in cases under m above, the block cannot become such a result)
  A aarg;  // for /.., the original a arg
  A lookaside;  // for local NAME, a pointer to the value for the primary table.  For primary tables, when this is non0, it must always match the value in the symbol table.  It is cleared to 0 when a NAME is allocated.  When a local value is assigned to a NAME with a negative bucketx,
         // we know that the NAME is the unique nameblock for all simple references to that name in that definition (it may be a clone of the original NAME bot it is still unique in that definition and used by ALL simple references including
         // assignments).  We save the assignment in the NAME block it is assigned to.  The value may change on reassignment.  When a local symbol table is cretaed or cloned, symbols are allocated for all PERMANENT (i. e. negative-bucketx) names
         // AND the symbol's name points to the shared name.  THIS WILL NEVER CHANGE - that's what PERMANENT means.  Therefore, whenever a negative-bucketx value is stored into a local table, we can update the lookaside value in the name block
         // pointed to by the symbol table.  If the value is deleted in the symbol table the lookaside must be cleared.
 } mback;
 union {  // 3
  I t;  // type
  A proxychain;  // used when block is on free chain
 } tproxy;
 I c;  // 4 usecount
//  NOTE!! result.h faux cellshape block depends on n, r, and s being in place from here to the end of this struct, with 2 Is from n to s
 I n;  // 5 # atoms - always 1 for sparse arrays.  In JOB block for task with locales, the thread mask
#if C_LE
 RANKT r;  // 6 rank.  Used as flags in SYMB types (i. e. locales)
 UC filler;
 US h;   // reserved for allocator.  Not used for AFNJA memory
#if BW==64
  // these two values initialized with a single store - must be in order
 US origin;  // 
 S lock;   // can be used as a lock
#endif
#else
#if BW==64
 S lock;   // can be used as a lock
 US origin;
#endif
 US h;   // reserved for allocator.  Not used for AFNJA memory
 UC filler;
 RANKT r;  // rank  Used as flags in SYMB types (i. e. locales)
#endif
 I s[1];   // 7 shape starts here.  NOTE!! s[0] is always OK to fetch.  We allocate 8 words minimum and s[0] is the last.
  // when AFUNIFORMITEMS is set, s[0] holds the number of items in the raze of the block
};
// header fits in 7 words

/* Fields of type A                                                        */

#define AK(x)           ((x)->kchain.k)        /* offset of ravel wrt x           */
#define AKASA(x)        ((x)->kchain.chain)       // the AK field for synthetic self blocks
#define AKGST(x)        ((x)->kchain.globalst)        // global symbol table for this local symbol table
#define AFLAG(x)        ((x)->flag)     /* flag                            */
#define AM(x)           ((x)->mback.m)        /* Max # bytes in ravel            */
#define ABACK(x)        ((x)->mback.back)        /* In virtual noun, pointer to backing block            */
#define AZAPLOC(x)      ((x)->mback.zaploc)    // on allocation, the address of the tstack entry that will free the block
#define AZAPLOCVOL(x)   (((volatile AD *)x)->mback.zaploc)    // on allocation, the address of the tstack entry that will free the block
#define AZAPLOCV(x)     ((A*)((x)->s[(x)->r]))    // for virtual blocks,  the address of the tstack entry that will free the block
#define AT(x)           ((x)->tproxy.t)        /* Type; one of the #define below  */
#define AC(x)           ((x)->c)        /* Reference count.                */
#define AN(x)           ((x)->n)        /* # elements in ravel             */
#define AR(x)           ((x)->r)        /* Rank                            */
#if PYXES
#define ARINIT(x,v)     {*(US*)&((x)->r)=(v);        /* Rank, clearing the high byte for initialization                           */ \
    *(I4*)&(x)->origin=THREADID1(jt);}   // save the originating thread and clear the lock to 0
#else
#define ARINIT(x,v)     *(US*)&((x)->r)=(v);        /* Rank, clearing the high byte for initialization                           */
#endif
#define SMMAH           7L   // number of header words in old-fashioned SMM alloc
#define NORMAH          7L   // number of header words in new system
#define AS(x)           ((x)->s)        // Because s is an array, AS(x) is a pointer to the shape, which is in s.  The shape is stored in the fixed position s.

// The following fields are used for private communication between /. and ;. and inside ;. for the fret buffer.
#define CUTFRETCHAIN(x) ((x)->kchain.chain)  // pointer to next block of frets
#define CUTFRETCOUNT(x) ((x)->kchain.k)  // when passed into cut, this is # frets.  Overwritten by CUTFRETCHAIN
#define CUTFRETFRETS(x) ((UC*)((x)->s))   // address of first fret
#define CUTFRETEND(x)   ((x)->n)   // address of last+1 fret

#if SY_64
#define AKXR(x)         (SZI*(NORMAH+(x)))
#define WP(t,n,r)       (SMMAH+ r   +(1&&t&LAST0)+(((t&NAME?sizeof(NM):0)+((n)<<bplg(t))+SZI-1)>>LGSZI))  // # I to allocate
#else
#define AKXR(x)         (SZI*(NORMAH+((x)|1)))
#define WP(t,n,r)       (SMMAH+(r|1)+  (1&&t&LAST0)+(((t&NAME?sizeof(NM):0)+((n)<<bplg(t))+SZI-1)>>LGSZI))
/* r|1 to make sure array values are double-word aligned */
#endif
#define AKX(x)          AKXR(AR(x))
#define RCALIGN         1   // the rank to use to put the data on a cacheline boundary

#define AV(x)           ( (I*)((C*)(x)+AK(x)))  /* pointer to ravel        */
#define AVn(n,x)          ( (I*)((C*)(x)+AKXR(n)))  // local array ravel
#define AV0(x)           ( (I*)((C*)(x)+AKXR(0)))  // local atom ravel
#define AV1(x)           ( (I*)((C*)(x)+AKXR(1)))  // pointer to ravel in known-local list
#define AV2(x)           ( (I*)((C*)(x)+AKXR(2)))  // pointer to ravel in known-local table
#define AV3(x)           ( (I*)((C*)(x)+AKXR(3)))  // pointer to ravel in known-local brick
#define BAV(x)          (      (B*)(x)+AK(x) )  /* boolean                 */
#define BAVn(n,x)         (      (B*)(x)+AKXR(n) )  // boolean non-virtual rank n
#define BAV1(x)         (      (B*)(x)+AKXR(1) )  // boolean non-virtual rank 1
#define BAV2(x)         (      (B*)(x)+AKXR(2) )  // boolean non-virtual rank 2
#define CAV(x)          (      (C*)(x)+AK(x) )  /* character               */
#define CAVn(n,x)         (((C*)(x)+AKXR(n)))  // character in non-virtual rank-n array
#define CAV0(x)         (((C*)(x)+AKXR(0)))  // character in non-virtual rank-0 array  (allocated as rank 0, that is)
#define CAV1(x)         (((C*)(x)+AKXR(1)))  // character in non-virtual rank-1 array
#define CAV2(x)         (((C*)(x)+AKXR(2)))  // character in non-virtual rank-2 array
#define UCAV(x)         (     (UC*)(x)+AK(x) )  /* unsigned character      */
#define UCAV0(x)        (     (UC*)(x)+AKXR(0) )  // local unsigned character atom
#define DSAV(x)          ( (DS*)((C*)(x)+AK(x)))  /* single-prec                */
#define USAV(x)         ((US*)((C*)(x)+AK(x)))  /* wchar                   */
#define USAVn(n,x)         ((US*)((C*)(x)+AKXR(n)))  // local wchar atom
#define USAV0(x)         ((US*)((C*)(x)+AKXR(0)))  // local wchar atom
#define USAV1(x)         ((US*)((C*)(x)+AKXR(1)))  // local wchar list
#define UAV(x)          (     (UC*)(x)+AK(x) )  /* unsigned character      */
#define UAVn(n,x)        (     (UC*)(x)+AKXR(n) )  // local unsigned character list
#define UAV1(x)         (     (UC*)(x)+AKXR(1) )  // local unsigned character list
#define UIAV(x)         ((UI*)((C*)(x)+AK(x)))  /* unsigned integer      */
#define UI4AV(x)        ((UI4*)((C*)(x)+AK(x)))  /* unsigned 32-bit int      */
#define UI4AV0(x)       ((UI4*)((C*)(x)+AKXR(0)))  // local unsigned 32-bit int atom
#define UI4AV1(x)       ((UI4*)((C*)(x)+AKXR(1)))  // local unsigned 32-bit int list
#define C4AV(x)         ((C4*)((C*)(x)+AK(x)))  /* literal4                */
#define C4AVn(n,x)      ((C4*)((C*)(x)+AKXR(n)))  // local literal4 list
#define C4AV1(x)        ((C4*)((C*)(x)+AKXR(1)))  // local literal4 list
#define NAV(x)          ((NM*)((C*)(x)+AKXR(1)))  // name, which is always allocated as rank 1, for some reason
#define NAVV(x)         ((volatile NM*)((C*)(x)+AKXR(1)))  // name, which is always allocated as rank 1, for some reason
#define IAV(x)          AV(x)                   /* integer                 */
#define I1AV(x)         ( (I1*)((C*)(x)+AK(x)))  /* pointer to ravel        */
#define I2AV(x)         ( (I2*)((C*)(x)+AK(x)))  /* pointer to ravel        */
#define I4AV(x)         ( (I4*)((C*)(x)+AK(x)))  /* pointer to ravel        */
#define I4AV0(x)        ((I4*)((C*)(x)+AKXR(0)))  // local unsigned 32-bit int atom
#define I4AV1(x)        ((I4*)((C*)(x)+AKXR(1)))  // local unsigned 32-bit int list
#define I8AV(x)         ( (I8*)((C*)(x)+AK(x)))  /* pointer to ravel        */
#define I8AV1(x)         ( (I8*)((C*)(x)+AKXR(1)))  /* pointer to ravel        */
#define IAVn(n,x)       ((I*)((C*)(x)+AKXR(n)))  // integer in a stack- or heap-allocated atom (rank n
#define IAV0(x)         ((I*)((C*)(x)+AKXR(0)))  // integer in a stack- or heap-allocated atom (rank 0 - used for internal tables)
#define IAV1(x)         ((I*)((C*)(x)+AKXR(1)))  // integer in a stack- or heap-allocated list (rank 1 - used for internal tables that need alignment or need AS[0])
#define IAV2(x)         ((I*)((C*)(x)+AKXR(2)))  // integer in a stack- or heap-allocated list (rank 2)
#define UIAV1(x)         ((UI*)((C*)(x)+AKXR(1)))  // unsigned integer "limb" in an X (or Q) value
#define BAV0(x)         ( (C*)((C*)(x)+AKXR(0)) )  // Boolean when rank is 0 - fixed position (known to avoid segfault)
#define LXAV0(x)        ( (LX*)((C*)(x)+AKXR(0)) )  // Symbol when rank is 0 - fixed position (for SYMB hash tables).  Note AK() is used in SYMB tables
#define LAV0(x)         ( (L*)((C*)(x)+AKXR(0)) )  // Symbol array when rank is 0 - used for the symbol pool
#define DAV(x)          ( (D*)((C*)(x)+AK(x)))  /* double                  */
#define DAVn(n,x)         ( (D*)((C*)(x)+AKXR(n)))  // double array
#define DAV0(x)         ( (D*)((C*)(x)+AKXR(0)))  // double atom
#define DAV1(x)         ( (D*)((C*)(x)+AKXR(1)))  // double list
#define DAV2(x)         ( (D*)((C*)(x)+AKXR(2)) )  // Double when rank is 2 - fixed position (for matrix inversion)
#define ZAV(x)          ( (Z*)((C*)(x)+AK(x)))  /* complex                 */
#define ZAVn(n,x)         ( (Z*)((C*)(x)+AKXR(n)))  // local complex array
#define ZAV0(x)         ( (Z*)((C*)(x)+AKXR(0)))  // local complex atom
#define ZAV1(x)         ( (Z*)((C*)(x)+AKXR(1)))  // local complex list
#define XAV(x)          ( (X*)((C*)(x)+AK(x)))  /* extended                */
#define XAVn(n,x)       ( (X*)((C*)(x)+AKXR(n)))  // local extended atom
#define XAV0(x)         ( (X*)((C*)(x)+AKXR(0)))  // local extended atom
#define XAV1(x)         ( (X*)((C*)(x)+AKXR(1)))  // local extended list
#define XAV2(x)         ( (X*)((C*)(x)+AKXR(2)))  // local extended brick
#define QAV(x)          ( (Q*)((C*)(x)+AK(x)))  /* rational                */
#define QAV0(x)         ( (Q*)((C*)(x)+AKXR(0)))  // local rational atom
#define QAV1(x)         ( (Q*)((C*)(x)+AKXR(1)))  // local rational list
#define EAV(x)          ( (E*)((C*)(x)+AK(x)))  // QP
#define EAV1(x)          ( (E*)((C*)(x)+AKXR(1)))  // QP list, always on cache bdy.  Other ranks are often adjusted to cache bdy
#define AAV(x)          ( (A*)((C*)(x)+AK(x)))  /* boxed                   */
#define AAVn(n,x)         ((A*)((C*)(x)+AKXR(n)))  // A block in a stack- or heap-allocated atom (rank n)
#define AAV0(x)         ((A*)((C*)(x)+AKXR(0)))  // A block in a stack- or heap-allocated atom (rank 0 - used for internal tables)
#define AAV1(x)         ((A*)((C*)(x)+AKXR(1)))  // A block in a stack- or heap-allocated list (rank 1)
#define AAV2(x)         ((A*)((C*)(x)+AKXR(2)))  // A block in a stack- or heap-allocated list (rank 2)
#define FAV(x)          ( (V*)((C*)(x)+AKXR(0)) )  // verb, adverb, conj - always at fixed offset
#define FAVV(x)         ( (volatile V*)((C*)(x)+AKXR(0)) )  // verb, adverb, conj volatile to avoid delayed fetch
#define PAV(x)          ( (P*)((C*)(x)+AK(x)))  /* sparse                  */
#define SBAV(x)         ((SB*)((C*)(x)+AK(x)))  /* symbol                  */
#define SBAVn(n,x)        ((SB*)((C*)(x)+AKXR(n)))  // local symbol
#define SBAV0(x)        ((SB*)((C*)(x)+AKXR(0)))  // local symbol atom
#define SBAV1(x)        ((SB*)((C*)(x)+AKXR(1)))  // local symbol list
#define SBUV4(x)        ((SBU*)((C*)(x)+AKXR(4)))  // symbol, nonvirtual rank 4
#define SYMBAV0(x)       ((LX*)((C*)(x)+AKXR(0)))  // symbol-table (LX) values (always alliocated at rank 0)
#define voidAV(x)       ((void*)((C*)(x)+AK(x)))  // unknown
#define voidAVn(n,x)     ((void*)((C*)(x)+AKXR(n)))  // unknown, but rank is known
#define voidAV0(x)       voidAVn(0,x)  // unknown, but scalar
#define voidAV1(x)       voidAVn(1,x)  // unknown, but list
#define voidAV2(x)       voidAVn(2,x)  // unknown, but table
#define voidAVCACHE(x)   voidAVn(RCALIGN,x)  // unknown, aligned to cache
#define UNLXAV0(x)      ((A)((I)(x)-AKXR(0)))   // go from a pointer to LXAV0 back to the base of the A block
#define UNvoidAV0(x)     ((A)((I)(x)-AKXR(0)))   // go from a pointer to *AV0 back to the base of the A block
#define UNvoidAV1(x)     ((A)((I)(x)-AKXR(1)))   // go from a pointer to *AV1 back to the base of the A block

#if C_LE
// use if there are upper flags #define BIV0(w) (IAV(w)[0]&(1-((AT(w)&INT)>>(INTX-1))))  // the first (presumably only) value in w, when w is an INT or B01 type
#define BIV0(w) (IAV(w)[0]&(((INT-1)-AT(w))>>1))  // the first (presumably only) value in w, when w is an INT or B01 type
#endif

// *************************************** Types for AT(x) field of type A ********************************/
/* Note: BOOL name conflict with ???; SCHAR name conflict with sqltypes.h  */

// NOTE!! the length of NOUN types must be power-of-2 multiples because of jtamend2

// NOTE: all noun types must be below all parsable non-nouns

#define B01X 0
#define B01             ((I)1L<<B01X)           // B  boolean
#define B01SIZE         sizeof(B)               // length of 1 atom
#define LITX 1
#define LIT             ((I)1L<<LITX)           // C  literal (character)
#define LITSIZE sizeof(C)
#define INTX 2
#define INT             ((I)1L<<INTX)           // I  integer
#define INTSIZE sizeof(I)
#define FLX 3
#define FL              ((I)1L<<FLX)            // D  double (IEEE floating point)
#define FLSIZE sizeof(D)
#define CMPXX 4
#define CMPX            ((I)1L<<CMPXX)          // Z  complex
#define CMPXSIZE sizeof(Z)
#define BOXX 5
#define BOX             ((I)1L<<BOXX)           // A  boxed
#define BOXSIZE sizeof(A)
#define XNUMX 6
#define XNUM            ((I)1L<<XNUMX)          // X  extended precision integer
#define XNUMSIZE sizeof(X)
#define RATX 7
#define RAT             ((I)1L<<RATX)           // Q  rational number
#define RATSIZE sizeof(Q)
// new types.  We could encode these as length+attributes, saving several bits, but since one-hot is good enough for now, we stay with it.
// The best encoded form I found is
// LEN1 LEN2 LEN4 CHAR LEN16/FL x SBT x   x C2T C4T     with the option of deleting C2T/C4T and turning on CHAR
// this allows clever encoding/decoding by keeping the length repetitive over byte-shifts
#define INT1X 8
#define INT1          ((I)1L<<INT1X)  // As the lowest set bit, 1-byte INT precision 5
#define INT1SIZE sizeof(B)
#define INT1EXTTYPE 5
#define INT2X 9
#define INT2          ((I)1L<<INT2X)  // As the lowest set bit, 2-byte INT precision 6
#define INT2SIZE sizeof(S)
#define INT2EXTTYPE 6
#define INT4X 10
#define INT4          ((I)1L<<INT4X)  // As the lowest set bit, 4-byte INT precision 7
#define INT4SIZE sizeof(I4)
#define INT4EXTTYPE 7
#define HPX 11
#define HP          ((I)1L<<HPX)  // As the lowest set bit, half-precision floating-point  precision 9
#define HPSIZE sizeof(US)
#define HPEXTTYPE 9
#define SPX 12
#define SP          ((I)1L<<SPX)  // As the lowest set bit, single-precision floating-point precision 10
#define SPSIZE sizeof(DS)
#define SPEXTTYPE 10
#define QPX 13
#define QP          ((I)1L<<QPX)  // As the lowest set bit, quad-precision floating-point precision 11
#define QPSIZE sizeof(E)
#define QPEXTTYPE 11
// 14-15 free
#define SBTX 16
#define SBT             ((I)1L<<SBTX)       // SB symbol
#define SBTSIZE sizeof(SB)
#define C2TX 17
#define C2T             ((I)1L<<C2TX)       // C2 unicode (2-byte characters)
#define C2TSIZE sizeof(US)
#define C2TEXTTYPEX  17
#define C4TX 18                  // must be C2TX+1
#define C4T             ((I)1L<<C4TX)       // C4 unicode (4-byte characters)

#define C4TSIZE sizeof(C4)
#define C4TEXTTYPEX  18
_Static_assert(C2TX+1==C4TX,"LIT4 and LIT2 bits must be contiguous");
#define XDX 19
#define XD              ((I)1L<<XDX)        // DX extended floating point   used to represent intolerant compare in jtiosc
#define XDSIZE sizeof(DX)
#define XZX 20
#define XZ              ((I)1L<<XZX)        // ZX extended complex
#define XZSIZE sizeof(ZX)

#define LASTNOUNX XZX    // index of last noun bit

// upper flags may be used, except for RPAR and CONJ (used as stack count in parser), LPAR and ASGN (used in parser to calculate initial stack count), CONW (always means ASGNTONAME in parser), NAME
// VERB/ADV/CONJ should not be used as flags in NOUN types.  The main flags are MARK/SYMB/CONW
// if ADV is used, some tests may need to change
// B01/INT must not have any upper flags at all
// NOTE: bit numbers for ADV, CONJ, and VERB, and 31, must be at least 2 bits apart because of code for type testing
#define NAMEX 21
#define NAME            ((I)1L<<NAMEX)    /* NM name                         */
#define NAMESIZE sizeof(C)   // when we allocate a NAME type, the length is the length of the name string
// NOTE: SYMB and MARK are used as flags in names, see below, and CONW in some type args
// MASK and ASGN are used in Vxxx flags
#define MARKX 22  // don't try to move this! it ripples through and breaks JTflags
#define MARK            ((I)1L<<MARKX)     // I  null argument, used when 0 won't do.  Deprecated
#define MARKSIZE sizeof(I)
#define ADVX 23
#define ADV             ((I)1L<<ADVX)      /* V  adverb                       */
#define ADVSIZE sizeof(V)
// NOTE: SYMB is set in an ADV value to indicate that the value is nameless, see below
#define ASGNX 24
#define ASGN            ((I)1L<<ASGNX)     /* I  assignment                   */
#define ASGNSIZE sizeof(I)     // only 1 byte, but all non-DIRECT are fullword multiples
// BOTE: SYMB and CONW are used as flags in ASGN, see below
#define SYMBX 25
#define SYMB            ((I)1L<<SYMBX)     /* I  locale (symbol table)        */
#define SYMBSIZE sizeof(LX)
#define CONWX 26
#define CONW            ((I)1L<<CONWX)    /* CW control word                 */
#define CONWSIZE sizeof(CW)
// NOTE: The parser assumes that CONW always means ASGNTONAME, so don't use it in any parseable type except ASGN
#define VERBX 27
#define VERB            ((I)1L<<VERBX)      /* V  verb                         */
#define VERBSIZE sizeof(V)  // Note: size of ACV in bp() is INTSIZE because the allocation in fdef() is of INTs
// NOTE: VERB must be above all NOUN bits because of CONJCASE.  Must be >ADV because of AVN testing in parser
// es delayline in parser expects VERBX <= 27
#define LPARX 28
#define LPAR            ((I)1L<<LPARX)    /* I  left  parenthesis            */
// note: LPAR used as flag to cvt() see below; also as modifier to ADV type
#define LPARSIZE sizeof(I)
// unquote requires that the spacing CONJX-ADVX equal VERBX-NAMEX
// CONJ must be 1 bit below RPAR to call for stacking 1 extra word after CONJ, 2 after RPAR
#define CONJX 29
#define CONJ            ((I)1L<<CONJX)     /* V  conjunction                  */
#define CONJSIZE sizeof(V)
#define RPARX 30
#define RPAR            ((I)1L<<RPARX)   /* I  right parenthesis            */
#define RPARSIZE sizeof(I)
#define PYXX 30  // overlaps RPAR.  We want the bare PYX bit to be enough to indicate a PYX when the contents of a box are interrogated with C().  RPAR
                         // is safe because it does not appear anywhere else except in sentences.  ADV/CONJ/VERB may appear in boxes in internal results, and LPAR may be
                         // set as a flag there
#define PYX          ((I)1L<<PYXX)  // if BOX set, this flag is set if the value is a pyx.  A pyx is an atomic box (which may be an element of an array).
                                    // Task creation returns an atomic box (which is NOT a pyx) that CONTAINS a pyx.  A pyx itself never becomes a result or argument, because
                                    // the value of a pyx may not be accessed except through C(pyx), which will return the address of the contents.  An A block pointing to the pyx (necessarily of BOX type)
                                    // can be freely stored into boxed arrays or returned as a result.  Our coding rule is that pyxes MAY be passed as a/w arguments, and may be stored unresolved in compounds; 
                                    // but they WILL NOT be passed as arguments into any other kind of routine.  The practical effect of this rule is that when a routine pulls the address of a box out of
                                    // an AAV area, any reference to the box's contents (AN, AR, AC, AT, AS, AK), or the value of the pyx,  requires C(pyx).
                                    // If the address of the pyx is being copied into another block, there is no need for C().  In particular, the pyx may be ra()'d if it is put into a recursive block.
                                    // ra() on a pyx will affect the usecount of the pyx itself but NOT of the contents, because a pyx is always marked recursive.
                                    // The pyx looks like an atomic box but it actually holds a PYXBLOK where the data would be.  The PYXBLOK begins with the result value, so that when
                                    // the pyx is freed the result will be also.  The AN of the 'atomic' pyx is initialized to 1, and AAV[0] to 0.  When the pyx is resolved, the address of the
                                    // result A block is stored into AAV[0], error code is saved in the PYXBLOK, and the executing thread field of the PYXBLOK is set to -1.
                                    // When a pyx is created, ownership is transferred to the enclosing box via zap.  The enclosing box is active in the creating task.  The PYXBLOK is ra()d
                                    // before it is passed to the executing task; the task fa()s it after it is filled in.
                                    //
                                    // NOTE that this definition of pyx doesn't match the user docs.  For the user, the pyx is the box enclosing what we have defined here as the true pyx.
                                    // This user-pyx can be passed as an argument, and is resolved when opened.  We document it this way because the user thinks of an array of 5 boxes
                                    // as being 5 containers, whereas really it is one BOX with pointers to 5 contents (which are true pyxes).

// Upper bits of a type can be used as flags, since we use CTTZ(AT) to indicate what the type is.  Usually we avoid these in NOUN types to
// make testing easier; but see BOXMULTIASSIGN which is never an argument

// ** ASGN type can have the following informational bits set along with ASGN
#define ASGNLOCALX      SYMBX     // set for =. (but not when assigning to locative)    aliases with SYMB
#define ASGNLOCAL       ((I)1L<<ASGNLOCALX)     // set for =. (but not when assigning to locative)    aliases with SYMB
#define ASGNTONAME      ((I)1L<<CONWX)     // set when assignment is to name    aliases with CONW
// NOTE: The parser assumes that CONW always means ASGNTONAME, so don't use it in any parseable type except ASGN
// ** NOUN types can have the following informational bits set
#define SPARSEX 31  // NOTE this extends to the sign bit
#if defined(_WIN64)||defined(__LP64__)
#define SPARSE            (-((I)1L<<SPARSEX))       /* P  sparse boxed                 */
#else
#define SPARSE            (IMIN)                    /* P  sparse boxed                 */
#endif
// ** NAME type can have the following information flags set
#define NAMEBYVALUEX    MARKX     // set if the name is one of u v u. v. that is always passed by value, never by reference
#define NAMEBYVALUE     ((I)1L<<NAMEBYVALUEX)
#define NAMEABANDONX SYMBX
#define NAMEABANDON            ((I)1L<<NAMEABANDONX)     // name is name::, which will be deassigned after the value is stacked.  NAMEBYVALUE must also be set
// ** BOX type can have the following informational flags set
#define BOXMULTIASSIGN  ((I)1L<<MARKX)     // set for the target of a direct multiple assignment (i. e. 'x y' =.), which is stored as a boxed list whose contents are NAMEs    aliases with MARK
// Restriction: CONW must be reserved for use as ASGNTONAME because of how parser tests for it
// Restriction: MARK must be reserved for use as BOXMULTIASSIGN because of how parser tests for it
// ** NOTE!! bits 22/24/26 are used in the call to cvt() (arg only) to override the conversion type for XNUMs
// MARK and ASGN hold the 2-bit rounding mode
#define XCVTXNUMORIDEMSK  (MARK+ASGN+CONW)   // in ccvt(), the override to use if XCVTXNUMORIDEX is set, otherwise 00
#define XCVTXNUMORIDEX  CONWX   // in ccvt(), indicates that forced precision for result is present
#define XMODETOCVT(x) (((((x)+2)&5)<<MARKX)|CONW)  // convert XMODE to a request to cvt to convert to that mode
#define CVTTOXMODE(x) ((((x)+MARK)>>(MARKX+1))&3) // convert cvt request back to xmode
// ** NOTE!! bit 28 are used in the call to cvt() (arg only) to indicate NOFUZZ
#define CVTNOFUZZX    LPARX     // 28 set if the name is one of u v u. v. that is always passed by value, never by reference
#define CVTNOFUZZ     ((I)1L<<CVTNOFUZZX)     // set if the name is one of x x. m m. etc that is always passed by value, never by name


// ***************************** flag combinations and macros ******************************

#define ANY             -1L
#define NUMERIC         (B01+INT+FL+CMPX+XNUM+RAT+INT2+INT4+SP+QP)
#define EXACTNUMERIC    (B01+INT+XNUM+RAT+INT2+INT4)
#define DIRECT          ((LIT+C2T+C4T+B01+INT+FL+CMPX+SBT+INT2+INT4+SP+QP+CONW)|SPARSE)  // AND must be >0
#define JCHAR           (LIT+C2T+C4T)
#define NOUN            (NUMERIC+JCHAR+BOX+SBT)
#define FUNC            (VERB+ADV+CONJ)
#define RHS             (NOUN+FUNC)
#define IS1BYTE         (B01+LIT)
#define LAST0           (B01+LIT+C2T+C4T+NAME)
#define SPARSABLE       (B01+INT+FL+CMPX+LIT)  // types that can be made sparse
// Don't traverse for ra/fa unless one of these bits is set
#define TRAVERSIBLE     (BOX|VERB|ADV|CONJ|RAT|XNUM|NAME|SYMB|SPARSE)
// Allow recursive usecount in one of these types
// A recursive block is flagged by having the recursible type bit copied into the AFLAG.  Presencve of a RECURSIBLE bit in the flag suffices to show that the block is recursive
// We know that any block that has been ra()d is recursive, and therefore that fa() can assume recursibility for any recursible type
#define RECURSIBLE      (BOX|VERB|ADV|CONJ|RAT|XNUM|NAME|SYMB)  // sparse box not allowed
// SYMB is TRAVERSIBLE so that fa() will call to free the symbols, and RECURSIBLE so that fanapop will pass the type-flag.  To ensure that a SYMB is always freed when
// its count goes to 0, we must ensure that it is always born recursive
#define RECURSIBLENOUN  (RECURSIBLE&NOUN)
#define SGN1IFSPARSETYPE(t,dt) ((t)&-((t)&(dt)))  // sign 1 if t is sparse and one of dt
#define SGN0IFDENSETYPE(t,dt) ((t)|(((t)&(dt))-1))  // sign 0 if t is dense and one of dt
#define ISDENSETYPE(t,dt) (((t)&SPARSE+(dt))>0)  // true if t is dense and one of dt
#define SGNIFSPARSE(t)  (t)  // set sign bit if t is sparse
#define ISSPARSE(t)     ((t)<0)  // true if sparse
#define SGNIFDENSE(t)   (~(t))  // set sign bit if t is dense
#define ISDENSE(t)      ((t)>=0)  // true if dense
// Modifiers that operate on subarrays do so with virtual blocks, and those blocks may be marked as inplaceable if the backing block is inplaceable.
// The inplaceability applies to the data area, but not necessarily to the block header: if UNINCORPORABLE is set, the header must not be modified (we clonevirtual() the header in that case)
// For speedy singletons, there is the additional problem that the operation expects always to write a FL value to the result area, which is OK for any
// real block but not for an inplaced virtual block, whose virtual data may be shorter than a FL.  The pure solution would be for the singleton code
// to refrain from modifying a virtual block that is shorter than a FL, but that means we would have to test for it for every arithmetic operation.  Thus
// we take the alternative, which is to not mark a virtual block inplaceable if it is a type shorter than a FL.
//
// BOX type would be OK, as singleton code doesn't touch it and all usecounts are held in the backer, except for the possibility that the backer is recursive and the virtual block isn't.
// Places that check TYPEVIPOK make an exception when the block is going to be processed by each or each2, because those routines are guaranteed not to disturb the boxes, but only
// the first level of contents, and that only when the block is pristine.
//
// Note: arithmetic dyads on bytes have similar issues, because the 8-byte-at-a-time operations may execute outside the cell of the array.  We detect
// those cases inside the atomic-dyad code in va2.c.
#define TYPEVIPOK       (FL+CMPX+SBT+(SZI==SZD?INT:0))  // sparse is never inplaceable
#define TYPESEQ(x,y)    ((x)==(y))  // types are equal
#define TYPESXOR(x,y)    ((x)^(y))  // types are not equal using full-word logical
#define TYPESNE(x,y)    ((x)!=(y))  // types are not equal
#define TYPESLT(x,y)    ((UI)(x)<(UI)(y))  // type x < type y
#define TYPESGT(x,y)    ((UI)(x)>(UI)(y)) // type x > type y

#define PARTOFSPEECHEQ(x,y) (((((x)|(LPAR&-((x)&NOUN)))^((y)|(LPAR&-((y)&NOUN))))&LPAR+CONJ+VERB+ADV)==0)  // using LPAR to hold NOUN status, verify parts-of-speech the same
#define PARTOFSPEECHEQACV(x,y) ((((x)^(y))&CONJ+VERB+ADV)==0)  // verify known-nonnoun parts-of-speech the same - enough is either value known to be ACV

// Utility: keep the lowest 1 only
#define LOWESTBIT(x)    ((x)&-(x))

#define POSIFHOMO(s,t)  ( -(((s)^(t))&(BOX|SBT|JCHAR|MARK)) & -(((s)^(t))&(BOX|SBT|NUMERIC|MARK)) )
#define NEGIFHOMO(s,t)  ( ~POSIFHOMO(s,t) )
#define HOMO(s,t)       ( POSIFHOMO(s,t)>=0 )
#define HOMONE(s,t)     HOMO(s,t)
#define STYPE(t)        ((t)|SPARSE)
#define DTYPE(t)        ((t)&~SPARSE)

// ********************** Flags in the count field of type A **************************

#define ACINPLACEX      (BW-1)
#define ACINPLACE       ((I)((UI)1<<ACINPLACEX))  // set when this block CAN be used in inplace operations.  Always the sign bit.
#define ACPERMANENTX    (BW-2)
#define ACPERMANENT     ((I)1<<ACPERMANENTX)  // next-to-top bit, set in blocks that should never modify the AC field
#define ACUSECOUNT      (I)1  // lower bits used for usecount
#define ACAND(a,v)      __atomic_fetch_and(&AC(a),(v),__ATOMIC_ACQ_REL);
#define ACOR(a,v)       __atomic_fetch_or(&AC(a),(v),__ATOMIC_ACQ_REL);
#define ACIPYESLOCAL(a)  (AC(a)|=ACINPLACE)
#define ACIPISOK(a)     (AC(a)<1)  // OK to modify if INPLACE set - set only when usecount=1
#define ACUC(a)         (AC(a)&(~ACINPLACE))  // just the usecount portion
#define ACUC1           (ACUSECOUNT*1) // <= this is usecount==1; > is UC>1
#define ACUC2           (ACUSECOUNT*2) // <= this is usecount<=2, which is inplaceable if you know the usecount has been uncremented earlier
#define ACADDLOCAL(a,n) if(likely(!ACISPERM(AC(a))))(AC(a)=(AC(a)+(n))&~ACINPLACE)
#define ACSUBLOCAL(a,n) if(likely(!ACISPERM(AC(a))))(AC(a)=(AC(a)-(n)))
// use ACINCR... when you know the block is recursive & you just want to adjust the usecount. POS means you know it is >0.  SP means it might be sparse (which always requires recursion)
#define ACINCRVIRT(a)   (AC(a)=(AC(a)&~ACINPLACE)+1)
#define ACIPNO(a)       {if(AC(a)<0)AC(a)&=~ACINPLACE;}  // if AC<0, the block must not be visible to other threads
#define ACIPNOABAND(a)  {AC(a)&=~ACINPLACE;}  // block is known to be inplace abandoned & thus not PERMANENT
#define ACADD(a,n)      if(AC(a)<0)__atomic_store_n(&AC(a),(n)+1,__ATOMIC_RELEASE);else if(likely(!ACISPERM(AC(a))))__atomic_fetch_add(&AC(a),(n),__ATOMIC_ACQ_REL);
#define ACINCR(a)       ACADD(a,1)
#define ACDECRNOPERM(a)  __atomic_fetch_sub(&AC(a),1,__ATOMIC_ACQ_REL)  // must not be PERM
#define ACINIT(a,v)     AC(a)=(v);  // used when it is known that a has just been allocated & is not shared
#define ACRESET(a,v)    AC(a)=(v);  // used when it is known that a is not shared (perhaps it's UNINCORPABLE)
#define ACSETLOCAL(a,v) AC(a)=(v);  // used when a might be shared, but atomic not needed
#define ACSET(a,v)      __atomic_store_n(&AC(a),(v),__ATOMIC_RELEASE);  // used when a might be shared, but atomic not needed
#define ACFAUX(a,v)     AC(a)=(v);  // used when a is known to be a faux block
#define ACINITZAP(a)    {*AZAPLOC(a)=0; ACINIT(a,ACUC1)}  // effect ra() after allocation, by zapping: used when we are not sure the most-recent value on the stack is a
#define ACINITUNPUSH(a) {A *pushp=jt->tnextpushp; --pushp; \
                          if(unlikely(((I)pushp&(NTSTACKBLOCK-1))==0)){A *nextp=(A*)*pushp; if(unlikely(nextp!=pushp-1))freetstackallo(jt); pushp=nextp;} /* check start of block and start of allo */ \
                          jt->tnextpushp=pushp; ACINIT(a,ACUC1)}  // effect ra() immediately after allocation, by backing the tpush pointer (like a ZAP but without AM)
#define ACINITZAPRECUR(a,t) {*AZAPLOC(a)=0; ACINIT(a,ACUC1); AFLAG(a)|=(t)&RECURSIBLE;}  // effect ra() immediately after allocation, by zapping, and make the block recursive if possible
#define ACZAPRA(x)      {if(likely(AC(x)<0)){*AZAPLOC(x)=0 ACIPNO(x);}else ra(x);}
#define ACX(a)          {AC(a)=ACPERMANENT; AFLAGORLOCAL(a,AT(a)&RECURSIBLE);}   // used only in initializations
#define ACISPERM(c)     ((I)!!(ACPERMANENT&(UI)(c)))  // is PERMANENT bit set?
#define ACSETPERM(x)    {AC(x)=ACPERMANENT+100000; __atomic_fetch_or(&AFLAG(x),(AT(x)&RECURSIBLE),__ATOMIC_ACQ_REL);}  // Make a block permanent from now on.  In case other threads have committed to changing the usecount, make it permanent with a margin of safety
#define SGNIFPRISTINABLE(c) ((c)+ACPERMANENT)  // sign is set if this block is OK in a PRISTINE boxed noun
// s is an expression that is neg if it's OK to inplace
#if SY_64
// Note: the following will fail if bit 63 of address may differ between jt->zombieval and w.  That will not be in my lifetime.  When it happens, perhaps clang will have fixed the version above not to create a branch
#define ASGNINPLACENEG(s,w)  ((s)&(AC(w)|(((I)jt->zombieval^(I)w)-1)))   // neg if OK to inplace ordinary operation, either because the block is inplaceable or because it's an assignment to zombie
#else
#define ASGNINPLACENEG(s,w)  ({I c=AC(w); c=jt->zombieval==w?-1:c; (s)&c;})   // clang17 generates a branch for this
#endif
#define ASGNINPLACESGN(s,w)  (ASGNINPLACENEG(s,w)<0)
#define ASGNINPLACESGNNJA(s,w)  ASGNINPLACESGN(s,w)
// define virtreqd and set it to 0 to start, and lgatomsini to lg(#atoms of type in an I)
// This is used in apip.  We must ALWAYS allow inplacing for NJA types, but for ordinary inplacing we don't bother if the number of atoms of w pushes a over a power-of-2 boundary
#define EXTENDINPLACENJA(a,w) \
  ( ((AC(a)&((((AN(a)+((NORMAH+1)<<lgatomsini)-1)+AN(w))^(AN(a)+((NORMAH+1)<<lgatomsini)-1))-(AN(a)+((NORMAH+1)<<lgatomsini)-1)))<0) || /* inplaceable value that will probably fit */ \
    ( ((((((AN(a)+((NORMAH+1)<<lgatomsini)-1)+AN(w))^(AN(a)+((NORMAH+1)<<lgatomsini)-1))-(AN(a)+((NORMAH+1)<<lgatomsini)-1))|SGNIF(AFLAG(a),AFNJAX))<0) &&  /* value will probably fit OR is NJA, where any fit MUST be used */\
      (jt->zombieval==a || (virtreqd=(AFLAG(a)>>AFKNOWNNAMEDX)&(((AC(a)^ACUC2)|(AFLAG(a)&(AFRO|AFVIRTUAL)))==0))>(UI)jt->zombieval) /* asg-in-place or virt extension.  Remember if virt extension  */ \
        /* virt extension is (x { (a , item)).  We require a to be named so that we know that usecount of 2 means value is stacked only once */ \
        /* we require zombieval=0 so that (a =. b , 5) will not create a virtual that must immediately be realized */ \
        /* the other requirements for inplacing are AC=2 and not VIRTUAL or RO */ \
    )  /* OK to inplace assignment/virtual */ \
  )

// ************************************ Values for AFLAG(x) field of type A ***********************************

// the flags defined here must be mutually exclusive with TRAVERSIBLE

#define AFRO            (I)1            /* read only; can't change data  matches B01    */
#define AFROX           0            /* read only; can't change data    */
#define AFNJAX          1            /* non-J alloc; i.e. mem mapped matches LIT   */
#define AFNJA           ((I)1<<AFNJAX)
#define AFDEBUGRESULTX  2           // special flag for values that alter debug state matches INT
#define AFDEBUGRESULT   ((I)1<<AFDEBUGRESULTX)
#define AFHADPARENX     3     // in an explicit-defn word, set if user's original had () around the value  matches FL
#define AFHADPAREN      ((I)1<<AFHADPARENX)
// obsolete  Note: bit 4 is LABANDONED which is merged here
#define AFUNDISPLAYABLEX  4           // value is INDIRECT but may contain zeros or invalid pointers
#define AFUNDISPLAYABLE   ((I)1<<AFUNDISPLAYABLEX)

#define AFSENTENCEWORDX     8     // matches INT1X
#define AFSENTENCEWORD      ((I)1<<AFSENTENCEWORDX)   // this block comes from an executing sentence and is protected by it
#define AFANCHOREDX     9     // matches INT2X
#define AFANCHORED      ((I)1<<AFANCHOREDX)   // this block must not be aliased (it is needed inplace)
#define AFUNINCORPABLEX SBTX      // matches SBTX 16
#define AFUNINCORPABLE  ((I)1<<AFUNINCORPABLEX)  // (used in result.h) this block is a virtual block used for subarray tracking and must not
                                // ever be put into a boxed array, even if WILLBEOPENED is set, because it changes and is probably on the C stack rather than 
                                // allocated memory.  It must never become part of a named value (except that it can be assigned to the entirety of local x and y).  AFVIRTUAL must also be set.  If this block is
                                // inplaceable, the data may be overwritten but the header must not be: clonevirtual() in that case to get a modifiable header
#define AFVIRTUALX      C2TX      // matches C2TX 17
#define AFVIRTUAL       ((I)1<<AFVIRTUALX)  // this block is a VIRTUAL block: a subsequence of another block.  The data pointer points to the actual data, and the
                                 // m field points to the start of the block containing the actual data.  A VIRTUAL block cannot be incorporated into another block, and it
                                 // cannot be assigned, unless it is 'realized' by creating another block and copying the data.  We realize whenever we call ra() on the block,
                                 // except during the EPILOG, where we don't realize the block unless the real block is about to be freed.  Like PERMANENT blocks,
                                 // VIRTUAL blocks are always recursive so that fa() will not recur.  Virtual blocks are always freed from tpop.  Since it cannot be copied or realized,
                                 // the virtual block always has usecount of ACUC1 or ACUC1+ACINPLACE.  EXCEPTION: for the initial assignment to x/y in an explicit
                                 // definition, we allow assigning a virtual block, because we know that the block and its backer are allocated in a higher level
                                 // and can never be freed until the explicit definition finishes.  ra() is OK since all virtual blocks are recursive.  It is OK to fa() the block on exit
                                 // or on reassignment, because that will just decrement the usecount of the nonrecursive block.
                                 // VIRTUAL blocks are normally not inplaceable (since they are by definition aliased to another block), but the temporary
                                 // UNINCORPORABLE blocks created by partitioning modifers to track cells may be inplaceable, and a virtual block whose backer
                                 // has been abandoned may be marked inplaceable as well.
                                 // NOTE: AFVIRTUALX must be higher than any RECURSIBLENOUN type (for test in result.h)
#define AFKNOWNNAMEDX   C4TX      // matches C4TX 18   *** can be changed when block is shared
#define AFKNOWNNAMED    ((I)1<<AFKNOWNNAMEDX)      // set (often) in a value when the value is assigned to a name.  It is possible that the name will be deleted, in which case the flag will be cleared
                                  // even if the value is assigned to another name.  The purpose is to allow virtual extension: if you know that a value is assigned to a name, then only one
                                  // thread can encounter the value with AC=2, and that is safe for virtual extension.

// the spacing of VIRTUALBOXED->UNIFORMITEMS must match ZZFLAGWILLBEOPENED->ZZCOUNTITEMS
#define AFVIRTUALBOXEDX XDX   // matches XDX 19
#define AFVIRTUALBOXED  ((I)1<<AFVIRTUALBOXEDX)  // this block (created in result.h) is an array that is about to be opened, and thus may contain virtual blocks as elements
#define AFUNIFORMITEMSX MARKX     // matches MARK 22
#define AFUNIFORMITEMS  ((I)1<<AFUNIFORMITEMSX)  // It is known that this boxed array has contents whose items are of uniform shape and type; the total number of those items is in AM (so this block cannot be virtual)
#define AFPRISTINEX      ASGNX  // matches ASGN 24 - must be above all DIRECT flags   *** can be changed when block is shared
#define AFPRISTINE  ((I)1<<AFPRISTINEX)  // meaningful only for BOX type.  This block's contents were made entirely of DIRECT inplaceable or PERMANENT values, and thus can be
   // inplaced by &.> .  If any of the contents are taken out, the PRISTINE flag must be cleared, unless the block is never going to be used again (i. e. is inplaceable).
   // When a VIRTUAL block is created, it inherits the PRISTINE status of its backer; if the block is modified or a value escapes by address, PRISTINE status is cleared in the backer.
   // If a PRISTINE virtual block is realized, the backer must become non-PRISTINE (because its contents are escaping).
   // If a PRISTINE block is incorporated, it must lose PRISTINE status because it is no longer possible to know whether contents may have been fetched while the
   // block was incorporated.
   // NOTE: if a block becomes shared, the value of PRISTINE becomes immaterial
#define AFDPARENX CONWX     // matches CONW 26
#define AFDPAREN  ((I)1<<AFDPARENX)  // In the words of an external definition, this word replaced the original and must use linear rep for its display
   // MUST BE GREATER THAN ANY DIRECT FLAG (not including the SPARSE flag)
#define AFUPPERTRIX RPARX      // matches RPAR 30
#define AFUPPERTRI  ((I)1<<AFUPPERTRIX)  // (used in cip.c) This is an upper-triangular matrix
// NOTE: bit 28 (LPAR) is used to check for freed bufs in DEADARG

#define AFAUDITUCX      32   // this & above is used for auditing the stack (you must run stack audits on a 64-bit system)
#define AFAUDITUC       ((I)1<<AFAUDITUCX)    // this field is used for auditing the tstack, holds the number of deletes implied on the stack for the block
#define AFLAGINIT(a,v)  {AFLAG(a)=(v);}  // used when it is known that a has just been allocated & is not shared
#define AFLAGRESET(a,v) {AFLAG(a)=(v);} // used when it is known that a is not shared (perhaps it's UNINCORPABLE)
#define AFLAGFAUX(a,v)  {AFLAG(a)=(v);}  // used when a is known to be a faux block
#define AFLAGANDLOCAL(a,v)   {AFLAG(a)&=(v);}  // LOCAL functions are used when the block is known not to be shared
#define AFLAGORLOCAL(a,v)    {AFLAG(a)|=(v);}
// Once a block has been shared, the flags do not change except for PRISTINE, KNOWNNAMED, ANCHORED.  (Pristine only gets cleared, KNOWNNAMED is set and cleared).
// To make sure a word-wide change doesn't store an old value, we store into these flags using single-byte operations.  This will cause sharing in the exceedingly rare
// case of simultaneous modification, but it avoids the need for RFO cycles.
#if C_LE
#define AFLAGSETANCHORED(a) {((C*)&AFLAG(a))[1]|=AFANCHORED>>8;}
#define AFLAGCLRANCHORED(a) (((C*)&AFLAG(a))[1]&=~(AFANCHORED>>8))
#define AFLAGSETKNOWN(a) {((C*)&AFLAG(a))[2]|=AFKNOWNNAMED>>16;}  // if the value is ever exposed to another thread, the count will be too high for KNOWN to matter
#define AFLAGCLRKNOWN(a) (((C*)&AFLAG(a))[2]&=~(AFKNOWNNAMED>>16))
#define AFLAGSETPRIST(a) {((C*)&AFLAG(a))[3]|=AFPRISTINE>>24;}
#define AFLAGCLRPRIST(a) {((C*)&AFLAG(a))[3]&=~(AFPRISTINE>>24);}
#endif
#define AFLAGPRISTNO(a) if(unlikely(AFLAG(a)&AFPRISTINE))AFLAGCLRPRIST(a)  // the test is to ensure we don't touch PERMANENT blocks

// rank flags in the AR field of symbol tables.  The allocated rank is always 0
#define ARNAMEDX 0   // set in the rank of a named locale table.  This bit is passed in the return from jtsyrd1.  Never set in a local table
#define ARNAMED ((I)1<<ARNAMEDX)
// bit 1 not used
// the rest of the flags apply only to local symbol tables
#define ARLCLONEDX NMSHAREDX  // 2 set if this is a cloned local symbol table (in which symbol numbers are invalid); OR in a global table that suppresses the check for locally-defined names
#define ARLCLONED (1LL<<ARLCLONEDX)
#define ARHASACVX 3   // set if this local symbol table contains an ACV
#define ARHASACV ((I)1<<ARHASACVX)
#define ARLOCALTABLEX 4   // Set in rank of all local symbol tables.  This indicates that the first hashchain holds x/y info and should not be freed as a symbol
#define ARLOCALTABLE ((I)1<<ARLOCALTABLEX)
#define ARLSYMINUSE 32  // This bit is set in the rank of the original local symbol table when it is in use
#define ARINVALID 64  // This (named or numbered) symbol table was never filled in and must not be analyzed when freed
#define ARNAMEADDEDX 7  // Set in rank when a new name is added to the local symbol table.  We transfer the bit from the L flags to the rank-flag.  Keep as sign bit
#define ARNAMEADDED (1LL<<ARNAMEADDEDX)

#define SFNSIMPLEONLY 1   // to sfn: return simple name only, discarding any locative

#define FIXALOCSONLYLOWEST 4  // to fixa: replace only the first occurrence of u/v in each branch
#define FIXALOCSONLY 8  // to fixa: replace only u/v (IMPLOC)
#define FIXASTOPATINV 16  // to fixa: stop afixing a branch when it gets to a an explicit obverse

// AH field of all blocks
#define AFHRH(a) ((a)->h)    // the workarea



// ********************* explicit definition block *************************

// the compiled form of an explicit definition is an A block with rank 0 with AK pointing into the middle so that only the As are freed.
// The number of words is AN, while the number of control words+1 (NC) is AK-s (counting 4-byte values)
// the sequence is
// source line numbers (NC US values, accessed from the end - read only on error)
// go values (NC US values, accessed from the end) - cw# to go to on error, or in if./for./try./select construct
// tcesx values (NC UI4 values, accessed from the end)
// words of the sentence, counting up, no gap between words of adjacent cws  <-- data pointer is at the beginning of this part
//
// the block is allocated at rank 1 so the compare in jtredef works 
//
// macros to access the parts: nc is -(#cw+1) = ~#cw
#define CWBASE(x) AAV(x) // pointer to start of the sentence words (also the end of tcesx)  - using AK
#define CWNC(x) ((CAV(x)-(C*)((I)x+AKXR(1)))>>3)  // number of CWs including the sentinel at the end
#define CWTCESX(base,ci) (((UI4*)base)[ci]) // UI4 value containing tcesx
#define CWTCESX2(base,ci) *(UI8 *)((UI4*)base+ci-1) // UI8 value containing low half=tcesx for ~i+1, high half=tcesx for ~i
#define CWGO(base,nc,ci) ((S*)((UI4*)base+(nc)))[ci] // S value containing ~go value for ~i
#define CWSOURCE(base,nc,ci) ((US*)((UI4*)base+(nc)))[ci+(nc)] // US value containing original sentence number for ~i
typedef struct {
UI4 tcesx;  // cw type/canend/number of first word in the line
#define TCESXTYPEX 26  // top field, 6 bits, is control-word type (from w.h)
#define TCESXTYPE ((UI4)0x3f<<TCESXTYPEX)  // mask for field
#define TCESXCEX 24  // canend bits 24-25
#define TCESXCECANX TCESXCEX
#define TCESXCECAN ((UI4)1<<TCESXCECANX)  // set if this result can become the result of the defn
#define TCESXCECANTX (TCESXCEX+1)
#define TCESXCECANT ((UI4)1<<TCESXCECANTX)  // set if this result cannot become the result of the defn
#define TCESXSXMSK 0xffffff  // mask of word-number bits
 US go;  // line number.  Depends on type; can be loop-to point, failing-branch point, or error handler
 US source;  // source line number
} CW;

// ***************** debug stack frame *********************

#define DCPARSE  1      /* sentence for parser                                          */
#define DCSCRIPT 2      /* script              -- line()                                */
#define DCCALL   3      /* verb/adv/conj call  -- dbunquote()                           */
#define DCJUNK   4      /* stack entry is stale                                      */
#define DCPM     5      // postmortem entry

typedef struct DS{      /* 1 2 3 5                                                       */
 struct DS*dclnk;       /* x x x x   link to next stack entry                              */
 A dcy;                 // x x x    &tokens; text       ; right argument
 I dcn;                 /* x x x    #tokens; line #     ; ptr to executing value               */
 I dcix;                // x x x x  index ; next index (neg to abort)  ; cw# in exp def being executed, or to be exec next
 I dcj;                 /* x x x x  error#; prev index  ; error #                         */
 C dctype;              /* x x x x  type of entry (see #define DC*)                       */
 B dcsusp;              /* x   x x  1 iff begins a debug suspension or pm session                      */
 C dcss;                //   x x    1 if script is supplying sentences (0 if interrupted by prompt) ;single step code
 C dcnewlineno;         //     x    set when debug has installed a new line number into dcix
 C dcpflags;            //   x x x      ;prompt flags, see JTPRTYO  ; 1 if DCPM, which requires symfreeha on the symbol table when freed
 C dcredef;             //     x    set if this definition has been reassigned while running on top of stack
 C dcdyad;              //     x x  set if this is a dyadic verb execution
 C dcnmlev;             //     x    decoration for name: none > >> clear name
 A dca;                 /*     x x  fn/op name                                            */
 A dcf;                 /*     x x  self                                                 */
 A dcx;                 /*     x    left argument                                         */
 A dcloc;               /*     x x  local symb table                  */
 A dcc;                 /*     x x  control matrix   (0 if not explicit)                  */
 I dcm;                 /* x x x    ". nesting level; script index    */
 I dcstop;              /*     x    the last stop in this function                        */
} DST;

typedef DST* DC;

// ************************ parsing flags **************************

// LSB codes in value pointers.  Set by enqueue() and symbis(), used by parsea().  Means that all boxes must be aligned to cacheline boundaries and freeing boxes must ignore these flags
// type of 0000 is reserved to indicate 'no value'; 1-11 are the type bits (following LASTNOUNX) in order
// in the words of an explicit definition the words have QCNAMELKP semantics in bit 4-5:
#define QCMASK 0x3fLL   // all the LSB flags
#define QCWORD(x) ((A)((I)(x)&~QCMASK))  // the word pointer part of the QC
#define QCTYPE(x) ((I)(x)&QCMASK)  // the type-code part plus semantics-dependent bits
#define QCPTYPE(x) ((I)(x)&0xf)  // the type-code part only, 0-15 for the syntax units including assignment
#define QCINSTALLTYPE(x,t) ((A)((I)(x)|(I)(t)))  // install t into word-pointer x
#define QCBITOP(x,op,mask) (x=(A)((I)x op (mask)))
// values 0-11 are the same in all contexts:
// the CAVN types are selected for comp ease in the typeval field of an assigned value.  They are indexes into ptcol.
// The value which might also hold VALTYPESPARSE, or VALTYPENAMELESS which is converted to correct type before the lookup).  These types are seen only in valtypes in named blocks, which have QCSYMVAL semantics
#define ATYPETOVALTYPEACV(t) (CTTZI((t)>>(LASTNOUNX-1)))  // types 1=NOUN 4=ADV 7=SPARSE 8=VERB 10=CONJ  0 means 'no value'
#define ATYPETOVALTYPE(t) (((t)&NOUN)?(unlikely(ISSPARSE(t))?VALTYPESPARSE:QCNOUN):ATYPETOVALTYPEACV(t))  // types 1=NOUN 4=ADV 7=SPARSE 8=VERB 10=CONJ  0 means 'no value or type not wanted'
#define VALTYPETOATYPE(t) ((1LL<<(LASTNOUNX-1))<<(t))  // convert t from valtype form to AT form (suitable only for conversion to pt - actual noun type is lost)
#define QCNOUNX 0
#define QCNOUN ((LASTNOUNX-LASTNOUNX)+1)  // this bit must not be set in any non-noun CAVN type, i. e. not in ACV.  But it must be set in SPARSE.  It can be used to test for FUNC in a named QCTYPE
// note: code points 2-3 must be left unused so we don't mess up clearing the pull queue
#define QCADV  ((ADVX-LASTNOUNX)+1) // 4
// note: code point 5 must be left unused so we don't mess up clearing the pull queue
// 6 NAMELESS, which can be ADV or CONJ and must be distinguished during lookup
// 7 sparse noun
#define QCVERB  ((VERBX-LASTNOUNX)+1)  // 8
#define QCLPAR  ((LPARX-LASTNOUNX)+1)  // 9
#define QCCONJ  ((CONJX-LASTNOUNX)+1)  // 10
#define QCRPAR ((RPARX-LASTNOUNX)+1)  // 11   referred to implicitly by mask operation
#define QCNAMEASSIGNED ((NAMEX-LASTNOUNX)+1) // 2 name followed by copula
// bit 4 and code points 12-15 depend on the context.
// In the words of a sentence, created by enqueue(), they use QCSENTENCE semantics as follows:
 // the last AT type is RPAR, which is 11 (30-20+1)
 // copulas occupy 12-15, with 4 variants
#define QCASGN 0x0c // copula.  QCASGNISLOCAL and QCASGNISTONAME are modifiers
#define QCASGNISLOCAL 0x1 // =. preceded by nonlocative name
#define QCASGNISTONAME 0x2  // copula is preceded by name
 // named lookups have bit 5 set, and use other flags to indicate the type of name
#define QCISLKPNAME 0x20   // name requires lookup (i. e. not assigned)
#define QCNAMEBYVALUE 0x01   // combining flag - name is mnuvxy type
#define QCNAMEABANDON 0x08 // combining flag - name has _: - set only if not assigned
#define QCSENTTYPE(x) ((I)(x)&0xf+QCISLKPNAME)  // the meaningful parts of the sentence type.  QCNAMED is set or not for performance reasons
// Values stored in the symbol table have QCSYMVAL semantics:
#define QCNAMEDX 4  // set to indicate that this value came from a name
#define QCNAMED ((I)1<<QCNAMEDX)
#define SETNAMED(w) (A)((I)(w)|QCNAMED)
#define QCRAREQDX 5   // Value should be ra()d before stacking.  This is any global name or any sparse value.
#define QCRAREQD ((I)1<<QCRAREQDX)
#define ISRAREQD(w) ((I)(w)&QCRAREQD)  // true if value should be ra()d before stacking
#define SETRAREQD(w) (A)((I)(w)|QCRAREQD)
#define CLRRAREQD(w) (A)((I)(w)&~QCRAREQD)
// value types set when the value is stored into the symbol table:
#define VALTYPENAMELESS ((SYMBX-LASTNOUNX)+1) // 6 set in nameless non-locative ACV, to suppress reference creation.
#define VALTYPESPARSE ((CONWX-LASTNOUNX)+1)  // 7 set in sparse noun, which is the only type of a stored value that requires traverse.  Has bit 0 set, as befits a noun
#define NAMELESSQCTOTYPEDQC(q) q=(A)(((I)q&~0xf)+ATYPETOVALTYPEACV(AT(QCWORD(q))));  // q is name of NAMELESS QC; result has QC type for AT(q) with unchanged semantics
// In the LSBs returned by syrd1() bit 4 has QCNAMEDLOC semantics (bit 5 is garbage):
#define QCNAMEDLOCX 4  // set if the value was found in a named locale, clear if numbered
#define QCNAMEDLOC ((I)1<<QCNAMEDLOCX)  // set if the value was found in a named locale, clear if numbered
#define CLRNAMEDLOC(w) (A)((I)(w)&~QCNAMEDLOC)
// In the LSBs returned by syrd()  (stored by symbis()), bit 4 and the higher code points have QCFAOWED semantics:
#define QCFAOWEDX 5  // the value was ra()d when it was stacked and must be fa()d when it leaves execution.  Normally matches RAREQD.  It is OK to ra() unnecessarily but this flag has to match the action we took in syrd
#define QCFAOWED ((I)1<<QCFAOWEDX)
#define QCFAOWEDMSK (QCNAMED+QCFAOWED)  // the bits in FAOWED semantics (not including the type flags)
#define CLRQCFAOWEDMSK(w) (A)((I)(w)&~QCFAOWEDMSK)
#define SETFAOWED(w) (A)((I)(w)|QCFAOWED)
#define CLRFAOWED(w) (A)((I)(w)&~QCFAOWED)
#define ISFAOWED(w) ((I)(w)&QCFAOWED)  // is fa() required?
#define SETNAMEDFAOWED(w) (A)((I)(w)|QCFAOWED|QCNAMED)
#define SYMVALTOFAOWED(w) (w)  // convert SYMVAL semantics of syrd() result to QCFAOWED: FAOWED if GLOBAL
// When the value is pushed onto the parser stack, we use STKNAMED semantics: STKNAMED is set in any named ref and
// the FAOWED bit moves to bit 1 where it can be distinguished from a tstack pointer
#define STKNAMEDX 0
#define STKNAMED ((I)1<<STKNAMEDX)  // set if the address is the address of the arg (rather than of a tpop slot)
#define ISSTKNAMED(w) ((I)(w)&STKNAMED)  // is fa() required?
#define STKFAOWEDX 1   // set in parser stack if value had ra() performed when it was stacked (or if ra() was performed later while on the stack)
#define STKFAOWED ((I)1<<STKFAOWEDX)
#define STKREFRESHRQDX 2  // set in verb of a line 1-3 exec to indicate that tpop[aw] are stale and must be refreshed from the stack
#define STKREFRESHRQD ((I)1<<STKREFRESHRQDX)
#define SETSTKFAOWED(w) (A)((I)(w)|STKFAOWED)
#define CLRSTKFAOWED(w) (A)((I)(w)&~STKFAOWED)
#define ISSTKFAOWED(w) ((I)(w)&STKFAOWED)  // is fa() required?
#define ISSTKREFRESHRQD(w) ((I)(w)&STKREFRESHRQD)  // is refresh of tpop[aw] required?
#define SETSTKREFRESHRQD(w) (A)((I)(w)|STKREFRESHRQD)
#define STKNAMEDMSK (STKNAMED+STKFAOWED)  // the bits in FAOWED semantics (not including the type flags)
#define SETSTKNAMEDFAOWED(w) (A)((I)(w)|STKNAMEDMSK)  // set NAMED+FAOWED


// *********************** symbol table for names ***********************

#define SYMLINFO 0  // index of LINFO entry
#define SYMLEXECCT 1  // index of EXECCT for the locale
#define SYMLINFOSIZE 2     // Number of symbol-table entries that DO NOT root symbol chains, but instead are LINFO entries
// The MSB of LX values is used to indicate that the NEXT value is NOT permanent.  We do this so that we can visit all PERMANENT entries without ever
// touching a non-PERMANENT one.  By marking NON-permanent symbols with the sign bit, we allow the code for permanent symbols to assume the
// sign is 0, since the bucket #s are always for permanent symbols.  The end-of-chain pointer does not have the PERMANENT flag set
#define SYMNONPERMX 31
#define SYMNONPERM (I4)(1L<<SYMNONPERMX)   // flag set if next is non-permanent, or if an LX is invalid
#define SYMNEXT(s) ((s)&~SYMNONPERM)  // address of next symbol
#define SYMNEXTISPERM(s) ((s)>0)  // true if next symbol is permanent

typedef struct {
 A name;  // name on lhs of assignment; in LINFO, pointer to NM block.  May be 0 in zombie values (modified cached values)
 A fval;  // rhs of assignment with flags (QCSYMVAL semantics), or 0 for PERMANENT symbols that have not yet been assigned.  In LINFO, the number of a numbered locale, unused otherwise
#define MAKEFVAL(v,f) (A)((I)(v)|(f))  // combine value & flag for fval
 LX next;  // LX of next value in chain.  0 for end-of-chain.  SYMNONPERM is set in chain field if the next-in-chain exists and is not LPERMANENT.  Not used in LINFO
 S sn;  // script index the name was defined in.  Not used for LINFO
 C flag;  // Lxx flags, see below.  Not used for LINFO (AR is used for locale flags)
} L;  // name must come first because of the way we use validitymask[11]

// FOR EXECUTING LOCAL SYMBOL TABLES: AK() points to the active global symbol table, AM() points to the calling local symbol table.
// In all local symbol tables, the first 'hashchain' has the chain numbers for y/x; they are the first symbols in those chains, always permanent

// flags in L->flag
#define LCH             (I)1            /* changed since last exec of 4!:5 */
#define LPERMANENTX  1
#define LPERMANENT   ((I)1<<LPERMANENTX)  // set if the name is a local name assigned in the definition; these names are never deleted - the value is cleared instead
#define LINFO           (I)4            // Indicates the symbol-table entry is info only and the value is not a valid pointer (diags only)
#define LWASABANDONEDX  4
#define LWASABANDONED   ((I)1<<LWASABANDONEDX)  // set if the name was assigned from an abandoned value, and we DID NOT raise the usecount of the value (we will have changed INPLACE to ACUC1, though).
                                    // when the name is reassigned or deleted, we must refrain from fa(), and if the value still has AC=ACUC1, we should revert it to inplaceable so that the parser will free it
                                    // immediately
                                    // This value passes into AFLAGS and must not overlap anything there
#define LHASNAME        (I)32      // name is nonnull - this value is not used internally; it appears in the result of 18!:_2
#define LHASVALUE       (I)64     // value is nonnull - this value is not used internally; it appears in the result of 18!:_2
#define LREADONLY       (I)128   // symbol cannot be reassigned (it is xxx or xxx_index)

// ********************************** fields in Global symbol tables (aka locales) ***************************
// In Global symbol tables (including numbered) AK is LOCPATH, and AM is available for use
// The first L block in a symbol table is used to point to the locale-name rather than hash chains
#define LOCNAME(g) ((SYMORIGIN)[LXAV0(g)[SYMLINFO]].name)  // NM block for locale name, for both named and numbered
#define LOCNUMW(g) ((SYMORIGIN)[LXAV0(g)[SYMLINFO]].fval)  // locale number, for numbered locales
#define LOCNUM(g) (I)LOCNUMW(g)
#define LOCPATH(g) (g)->kchain.locpath   // the path, allocated with rank 1 (so the path is in one cacheline).  If 0, the locale has been deleted.  The path runs from LOCPATH backwards
                        // to end with the ending 0 at AAV1()[0]


// Macros to incr/decr execct of a locale
#define EXECCTNOTDELD 0x1000000   // This bit is set when a locale is created, and removed when the user asks to delete it.  Lower bits are the exec count.  The locale is half-deleted when exec ct goes to 0
#define EXECCTPERMX 25  // set to mark the locale permanent, execcts not tracked
#define EXECCTPERM ((I)1<<EXECCTPERMX)
#if PYXES
#define INCREXECCT(l) __atomic_fetch_add(&LXAV0(l)[SYMLEXECCT],1,__ATOMIC_ACQ_REL);
#define DECREXECCT(l) if(unlikely(__atomic_sub_fetch(&LXAV0(l)[SYMLEXECCT],1,__ATOMIC_ACQ_REL)==0))locdestroy(l);
#define DELEXECCT(l) if(unlikely(__atomic_and_fetch(&LXAV0(l)[SYMLEXECCT],~EXECCTNOTDELD,__ATOMIC_ACQ_REL)==0))locdestroy(l);
#else
#define INCREXECCT(l) ++LXAV0(l)[SYMLEXECCT];
#define DECREXECCT(l) if(--LXAV0(l)[SYMLEXECCT]==0)locdestroy(l);
#define DELEXECCT(l) if((LXAV0(l)[SYMLEXECCT]&=~EXECCTNOTDELD)==0)locdestroy(l);
#endif
#define INCREXECCTIF(l) {if(unlikely(!(LXAV0(l)[SYMLEXECCT]&EXECCTPERM)))INCREXECCT(l)}
#define DECREXECCTIF(l) {if(unlikely(!(LXAV0(l)[SYMLEXECCT]&EXECCTPERM)))DECREXECCT(l)}
#define DELEXECCTIF(l) {if(likely(!(LXAV0(l)[SYMLEXECCT]&EXECCTPERM)))DELEXECCT(l)}



// *********************** name block ************************

// NM struct: pointed to by the name field of a symbol (NAV(sym->name)), and used for lookups.  Names are allocated with rank 1
// the first cacheline contains the lookaside value pointer for the primary symbol table.  It is modified frequently by the primary and must not be referred to by other tables, for false sharing.
// the second cacheline contains data shared by all tables and must not be modified often (bucket is cleared when a name is long-cached)
typedef struct{
 I bucketx; // (for local simple names, only if bucket!=0) the number of chain entries to discard before
//   starting name search.  If negative, use one's complement and do not bother with name search - symbol-table entry
//   is guaranteed to be at that position
//   (for direct locatives) the hash of the locative - if numbered, the number itself.
//   (for indirect locatives) hash of the last indirect name
//   (for locale names in SYMLINFO of a numbered locale) the locale number
 A cachedref; // (only for cachable NAME blocks): the value to be used for this name entry, if it is not a noun.  Non-QC semantics.  It may be (1) in a nameless modifier, the A block for the value, which has PERMANENT AC
               // (2) otherwise, the nameref for the name block, which may or may not have the pointer to the looked-up value.  This nameref is not PERMANENT AC and must be deleted when the name is deleted
 LX symx;  // (only for SHARED names, which are only local variables and never cachable) the index of the symbol allocated in the primary symbol table.  Used for assignment
 I4 bucket; // (for local simple names) the index of the hash chain for this symbol when viewed as a local.  -1 for names in 6!:2 from keyboard, to bypass the check for local names in global assignment
//   0 if chain index not known or name is a locative
 UI4 hash;  // hash for non-locale part of name
 US n;  // length of entire name
 UC m; // length of non-locale part of name note 255-byte limit! (n holds the length of the entire name including the locative)
 C flag; //  flags for name (see below)
 C s[1];  // string part of full name (1 to ?? characters, including locale of assignment if given) up to 32 chars fit in a 128B allo
} NM;

// values in flag.  These are set at creation and not modified, & thus threadsafe
#define NMLOC           1       // direct   locative abc_lm_   only one of NMLOC/NMILOC/NMIMPLOC is set
#define NMILOC          2       // indirect locative abc__de__fgh ...     only one of NMLOC/NMILOC/NMIMPLOC is set
#define NMSHAREDX    2
#define NMSHARED     (1LL<<NMSHAREDX)      // This NM is for a locally-defined name and is shared by all references to the name
#define NMIMPLOC        16      // this NM block is u./v.     only one of NMLOC/NMILOC/NMIMPLOC is set
#define NMCACHEDX       5
#define NMCACHED        (1LL<<NMCACHEDX)      // This NM is to cache any valid lookup
#define NMMNUVXY           128       // one of the names m n u v x y


// ************************ sparse-array header ************************
typedef struct {I a,e,i,x;} P;

/* value fields of sparse array types                                      */
/* fields are offsets from beginning of the P struct                       */
/* a: sparse axes                                                          */
/* e: sparse element                                                       */
/* i: index matrix, columns correspond to a                                */
/* x: value cells corresponding to rows of i                               */

#define SPA(p,a)        ((A)((p)->a+(C*)(p)))  // a is one of aeix; result is A pointer for that component
#define SPBV(p,a,v,x)      {RZ(v = (x)); INCORP(v); (p)->a=(C*)v-(C*)(p);}  // store x into component (a); return if x is 0.  a is one of aeix.  Result in v
#define SPB(p,ZWa,x)      {A ZWo = (x); SPBV((p),ZWa,ZWo,(x))}  // store x into component (a); return if x is 0.  a is one of aeix

// ****************************************** Header for hashtables used in i. *****************************************
// This sits at the beginning of the allocated block, holding info about the stored values
typedef struct {
 I datasize;   // number of bytes in the data area
 I hashelelgsize;  // lg(size of a hashed element)
 UI currentlo;   // the lowest position in the hashtable of the current allocation.
 UI currenthi;   // the highest position+1 of the current allocation.
 UI currentindexofst;   // the value in the hashtable that the minimum value in the input will map to
 UI currentindexend;    // the highest value that can possibly be written, +1
 UI previousindexend;  // All positions from 0 to currenthi are known to be less than currentindexend.
             // Positions from currenthi to the end are known to be less than previousindexend.
 UI invalidlo;   // the start of the area that does not have constrained values because it was used for a bit table (as an index into hashtable, rounded up to multiple of I for endian reasons)
 UI invalidhi;   // the end+1 of the area used for a bit table  (as an index into hash table, rounded up to multiple of I)
 I datamin;  // (for small-range use) minimum value in the data
 UI datarange;  // (for small-range use) range+1 of the data
 D cct;  // if this is tolerant, the cct used to build the table
 // 12 words here; 7 words of header (we allocate no shape);  so this block is 19 words after the
 // memory allocation; add one fill to get on the same 256-bit boundary as the allocation.
 I filler;
 union {   // We index into the data with varying strides, depending on the range of the data
  UC UC[1];  // cannot have union of empty vectors
  US US[1];
  UI4 UI4[1];
  UI UI[1];
 } data;
} IH;
#define IHAV(x)         ((IH*)((C*)(x)+AK(x)))  //  how to refer to the header area
#define IHAV0(x)         ((IH*)((C*)(x)+AKXR(0)))  //  how to refer to the header area when it has rank 0

// Return value from condrange
typedef struct {
 I min;  // smallest value found
 I range;  // max+1-min, or 0 if range exceeds max given
} CR;

// *********************************** performance monitoring ********************************************

typedef struct{
 A name;                /* verb/adverb/conjunction name                    */
 A loc;                 /* locale name                                     */
 I lc;                  /* line number (-1 for entry; -2 for exit)         */
 I s;                   /* space                                           */
 I t[2];                /* time                                            */
 C val;                 /* valence: 1 or 2                                 */
 C unused[3];           /* padding                                         */
} PM;

#define PMCOL  6        /* # of fields in PM                               */

typedef struct{
 I n;                   /* maximum number of records                       */
 I i;                   /* index of next record to be written              */
 I s;                   /* initial bytesmax value                          */
 I pmctr;               // counter, set > 0 to start sampling
 B rec;                 /* what to record (0 entry & exit; 1 all)          */
 B trunc;               /* what to do on overflow (0 wrap; 1 truncate)     */
 B wrapped;             /* 1 iff wrapping has happened                     */
 C unused[1];           /* padding                                         */
} PM0;


// ***************************** red/black balanced trees ****************************
/* each unique symbol has a row in JT(jt,sbu)                                 */
/* a row is interpreted per SBU                                            */
/* for best results make sizeof(SBU) a multiple of sizeof(I)               */
 
typedef struct{
 I  i;                  /* index into sbs                                  */
 I  n;                  /* length                                          */
 UI h;                  /* hash value                                      */
 I  color;              /* binary tree: color                              */
 I  parent;             /* binary tree: index of parent                    */
 I  left;               /* binary tree: index of left  child               */
 I  right;              /* binary tree: index of right child               */
 I  order;              /* order number                                    */
 I  down;               /* predecessor in ordering                         */
 I  up;                 /* successor   in ordering                         */
 I  flag;               /* bit flags                                       */
} SBU;

#define SBC2  1         /* 1 iff 2-byte character                          */
#define SBC4  2         /* 2 iff 4-byte character                          */

// Info for calling an atomic verb
typedef struct {VF f;I cv;} VA2;  // for dyads
typedef struct {VA1F f;I cv;} VA1;  // for monads
typedef struct {VARPSF f;I cv;} VARPS;  // for reduce/prefix/suffix

typedef struct {I nprec; VARPS actrtns[];} VARPSA;
typedef struct {VA2 p2[17];VARPSA *rps;} VA;  // 9 main types, CMPX, XNUM, RAT, SBT, SP, QP, INT2, INT4
typedef struct {VA1 p1[10];} UA;  // B01, INT, FL, CMPX, XNUM, RAT, SP, QP, INT2, INT4

// ********************** layout of a FUNC (starts at AS[0]) ************************************
typedef struct {
 // the localuse fields are not freed or counted for space, as the f/g/h fields are.  They are for local optimizations only.
 union {
  // start with the larger localuse, which requires a second cacheline.  This is 16 bytes, the first 8 of which are in the excess (first) cacheline
  struct {AF func; I parm;} boxcut0;  // for x <;.0 y  and  x (<;.0~ -~/"2)~ y, .parm is ~0 for first, 0 for second, and .func points to failover routine (seldom used).  func in first cacheline
  I4 lslevels[3];  // dyad0, dyad1, monad level in L:/S:
  struct {
   union {
    I filler;  // pad to cacheline
    A cachedloc;   //  for namerefs ('name'~), the locale address if the name is a direct named lookup (after the first reference)
    A gerundself;  // in gerund iterators, the address of the self block for m@.v, for diagnostic purposes
    AF modatomfn;  // in u m. n, the verb to process atoms of u
   } lu0;
   // end of first cacheline, which is not used much during execution
   // the rest do not require both cachelines in 64-bit
   union {  // 8 bytes in the second (main) cacheline.  Aligned to 8-byte bdy even on 32-bit system
    D cct;  // for comparison tolerance, FIT conj  =!.n OR comparison combination (i.&1@:(e.[!.n])) OR [e. i. ([-.-.)]&n OR m&i[.:] the CCT, 0 for default (never in an actual prehash).  For 32-bit, this extends the union, but that's OK since it doesn't add a cacheline.
    struct {
     I4 cgerx; // For cyclic iterators, the index of the next gerund to execute.  Here to avoid conflict with cut
     I4 cutn;  // for u;.n where n is nonzero, n.  u/. also goes through this code.  There could be cyclic iterators but not boxcut
    } gercut;
    VARPSA *redfn;  // for reductions (u/ u/\ u/\.) address of rps block (may be dummy block)
    US uavandx[2];   // offset from start of va/va1tbl to VA/UA block for adocv [monad then dyad]
    A wvb;  // for u&.[:]v, the verb whose inverse is needed
    I linkvb;  // for dyads ; (,<) ,&[:]<  indicates which function; for (compare[!.n] |), indicates which compare function
    A cachedlkp;  //  for namerefs ('name'~), the cached value, or 0 if not cached.   No QC semantics
    AF fork2hfn;   // for dyad fork that is NOT a comparison combination or jtintersect, the function to call to process h (might be in h@][)
    I forcetask;  // for t., the flags extracted from n.  Bits 0-7=thread pool; bit 8=worker thread only 32+=locales given
    I fittype;  // for u!.t where t is a code, its value is stored here in the CFIT block; for $!.v, 0 if the ultimate routine is ($,), 1 if $
    I1 srank[4];   // for RANK conj, the signed ranks.  srank[3] is nonzero if the given rank was floating-point - means 'don't combine'
    UI mrecip;  // for u m. n  m&|@^ and m&|@(n&^), the reciprocal of m, with binary point above 2^BW
    S foreignmn[2];  // in m!:n, the arguments
    I poweratom;  // for u^:atom or u^:<any, the encoded arg status: bit0=multiple (i. e. boxed n) bit1=nonneg power bits2-31=|power|
    AF bondfn;  // for m&v u&n, the dyad entry point for u/v
    I sundern;  // for u&.v structural under, form of u: 0=, 1=m&{ 2=m&(];.0)
   } lu1;  // this is the high-use stuff in the second cacheline
  };
 } localuse;  // always 16 bytes, 4 I4s
 A fgh[3];  // operands of modifiers.  h is used for forks and also as a storage spot for parms.  all 3 are freed when the V block is freed
 AF valencefns[2];   // function to call for monad,dayd
 I4 flag;
 UI4 flag2;
 RANK2T lrr;  // combining dyad ranks: (left<<RANKTX)|right
 RANKT mr;  // combining monad rank
 C id;  // pseudochar for the function encoded here
union{
 C lc;  // lc is a local-use byte.  Used in atomic verbs to indicate which singleton function to execute.  in the derived function from fold, lc has the original id byte of the fold op
 UI4 refvalidtime;  // for namerefs, the value of JT(jt,fnasgnct) when the cached value was looked up
} lu2;
} V;  // two cachelines in 64-bit (16 Is); 20 I4s in 32-bit
// The AN and AR fields of functions are not used

// cut-down version of V, used only for executing atomic combinations
typedef struct {
 // the localuse fields are not freed or counted for space, as the f/g/h fields are.  They are for local optimizations only.
 union {  // 8 bytes in the second (main) cacheline
    D cct;  // for comparison tolerance, FIT conj  =!.n OR comparison combination (i.&1@:(e.[!.n])) OR [e. i. ([-.-.)]&n OR m&i[.:] the CCT, 0 for default (never in an actual prehash).  For 32-bit, this extends the union, but that's OK since it doesn't add a cacheline.
    struct {
     I4 cgerx; // For cyclic iterators, the index of the next gerund to execute.  Here to avoid conflict with cut
     I4 cutn;  // for u;.n where n is nonzero, n.  u/. also goes through this code.  There could be cyclic iterators but not boxcut
    } gercut;
    VARPSA *redfn;  // for reductions (u/ u/\ u/\.) address of rps block (may be dummy block)
    US uavandx[2];   // offset from start of va/va1tbl to VA/UA block for adocv [monad then dyad]
    AF foldfn;  // for Fold final operator, pointer to the dyadic EP of the handler (xdefn or unquote)
    A wvb;  // for u&.[:]v, the verb whose inverse is needed
    I linkvb;  // for dyads ; (,<) ,&[:]<  indicates which function; for (compare[!.n] |), indicates which compare function
    A cachedlkp;  //  for namerefs ('name'~), the cached value, or 0 if not cached
    AF fork2hfn;   // for dyad fork that is NOT a comparison combination or jtintersect, the function to call to process h (might be in h@][)
    I forcetask;  // for t., the flags extracted from n.  Bits 0-7=thread pool; bit 8=worker thread only
 } lu1;  // this is the high-use stuff in the second cacheline
 AF valencefns[2];   // function to call for monad,dayd
 A fgh[3];  // operands of modifiers.  h is used for forks and also as a storage spot for parms.  all 3 are freed when the V block is freed
 I4 flag;
 UI4 flag2;
 RANK2T lrr;  // combining dyad ranks: (left<<RANKTX)|right
 RANKT mr;  // combining monad rank
 C id;  // pseudochar for the function encoded here
 C lc;  // lc is a local-use byte.  Used in atomic verbs to indicate which singleton function to execute.  in the derived function from fold, lc has the original id byte of the fold op
// 3 bytes free
} exeV;  //one cacheline

#define IDD(f) FAV(AT(f)&FUNC?(f):FUNCID0)->id  // id of a value known to be defined but possibly not an ACV
#define ID(f)  FAV(AT((f)?(f):FUNCTYPE0)&FUNC?(f):FUNCID0)->id  // id of possibly 0 value
#define VFLAGNONE 0L
#define VRTNNONE ((A)0)
                                        /* type V flag values              */
// bits 0-6 are used in comparison compounds to encode the type of compound, see vcompsc.c
// They must have this setting when the verb is fit u!.n or -. ([ -. -.) i. i: e. or a comparison compound
// They are examined during u&n and m&v processing.  Bits 0-2 are the comparison type, bit 3-5 are the action type.
// NOTE: comparison type e. is type 7.  If u&n sees bits 0-2=111 in u, it will generate a hashtable.  To prevent this from
// happening incorrectly, leave bit 2=0.
#define VFCOMPCOMP      0xff  // flag bits for comparison compounds, also used for other purposes
// NOTE: comparison flags pun with VFATOP[RL] in (comp i[.:] [01]:) but that's OK because if the function reverts, it turns off inplacing
// for other types, they are defined as follows:
#define VFATOPL         JTINPLACEW     // (in execution of forks and v0`v1`v2) f/v0 is x@[, so OK to inplace w arg of h
#define VFATOPR         JTINPLACEA     // (in execution of forks and v0`v1`v2) f/v0 is x@], so OK to inplace a arg of h
#define VFHKLVLDECX     0   // (in (compare L.) hooks) set for > and <: to indicate increment of x needed before levelle
#define VFHKLVLDEC      (((I)1)<<VFHKLVLDECX)
#define VFHKLVLGTX      1   // (in (compare L.) hooks) set for < and <: to indicate complement of result of levelle needed
#define VFHKLVLGT       (((I)1)<<VFHKLVLGTX)
#define VFSCANIRSX     0   // (in u/\) set if u supports IRS2
#define VFSCANIRS      (((I)1)<<VFSCANIRSX)
#define VFUNDERHASINVX  0  // (in u&.[:]v) set if h has the inverse already added
#define VFUNDERHASINV      (((I)1)<<VFUNDERHASINVX)
#define VFATOPPOLYX  0  // (in p.) the function to run after p.  0=none, 1=^
#define VFATOPPOLY      (((I)3)<<VFATOPPOLYX)
#define VFATOPPOLYNONE  0
#define VFATOPPOLYEXP  1
#define VFKEYSLASHTX  0  // (in f/.) set if f is u/ where u is one of + <. >., indicating which types are OK for atoms (can't handle int ovfl)
#define VFKEYSLASHT      (((I)(2*FL-1))<<VFKEYSLASHTX)
#define VFKEYSLASHFX  (FLX+1)  // (in f/.) function coded for, 0=<. 1=>. 2=+
#define VFKEYSLASHF      (((I)3)<<VFKEYSLASHFX)
#define VISDDX     0   // (in 9 : n) explicit def was from {{ }}
#define VISDD      (((I)1)<<VISDDX)
#define VDDHASCTLX      1   // (in 9 : n) explicit def had {{)
#define VDDHASCTL       (((I)1)<<VDDHASCTLX)

// leave bit 2 open

// bits 8 and above are available for all verbs:
#define VGERLX          8
#define VGERL           (((I)1)<<VGERLX)          /* gerund left  argument           */
#define VGERR           (I)512          /* gerund right argument           */
// bit 10 free
#define VIRS1X          11
#define VIRS1           (I)2048         /* 11 monad has integral rank support */
#define VIRS2X          12
#define VIRS2           (((I)1)<<VIRS2X)         /* 12 dyad  has integral rank support */
#define VFLR            (I)0x2000         /* function is <.@g                */
#define VCEIL           (I)0x4000       /* function is >.@g                */
// bit 15 free
#define VLOCK           (I)0x10000        /* function is locked              */
#define VWASUNARY       (I)0x20000       // 17 this verb replaces the original, which was something like -: that is replaced by 0.5 *
#define VFIX            (I)0x40000       /* f. applied                      */
#define VXOPRX          19                // the definition is an explicit modifier that refers to x or y
#define VXOPR           ((I)1<<VXOPRX)
#define VXOP            (I)0x100000      // this is the result of giving [u]/v args to a defn that had VXOPR set.  u and v are in fgh[0/2]
#define VTRY1           (I)0x200000      /* monad contains try.             */
#define VTRY2           (I)0x400000      /* dyad  contains try.  must be just above VTRY1           */
#define VUNARYCODEX      23                //  2-bit field indiating the original verb (when taken with id)
#define VUNARYCODE0     ((I)0<<VUNARYCODEX)
#define VUNARYCODE1     ((I)1<<VUNARYCODEX)
#define VUNARYCODE2     ((I)2<<VUNARYCODEX)
#define VUNARYCODE3     ((I)3<<VUNARYCODEX)
// bit VASGSAFE is wired into a flag reg in parser
#define VXOPCALL       (I)0x2000000      // 25 this verb is a namerefop, interposed to hang a name for debugging onto an anyymous verb.  f is 0, the name is in g, the actual verb in h     overlaps SYMB/ASGNLOCAL
#define VASGSAFEX     26
#define VASGSAFE      (((I)1)<<VASGSAFEX)     // Execution does not alter locale/path.
// 27 free   it appears that u !: n forms were envisaged
#define VISATOMIC1      ((I)(1L<<28))     // processes each atom individually (logically rank 0, but handles all ranks)
#define VISATOMIC2      ((I)(1L<<29))    // dyad is atomic.  localuse will point to the VA entry for the verb
#define VFUSEDOK2  ((I)(1L<<30))    // this block can be executed by passing in another block (containing rank) whose fgh[0] points to the native block for this primitive

// bits in flag2:
#define VF2NONE 0
// bit 0 unused
#define VF2BOXATOP1X      1   // This verb is one of  <  <@f   <@:f   <&f   <&:f    f&.>  f&.:>
#define VF2BOXATOP1     ((I)(((I)1)<<VF2BOXATOP1X))
#define VF2BOXATOP2X      2   // This verb is one of  <@f   <@:f   f&.>  f&.:>
#define VF2BOXATOP2     ((I)(((I)1)<<VF2BOXATOP2X))
// next 2 flags must be adjacent as we carry from one to the other
#define VF2WILLOPEN1PROPX  3   // If WILLBEOPENED is set in jt coming into this verb, it should be passed through to the execution of the verb producing y.  Monadic case.  Cannot be set if WILLOPEN is set.
                           // Setting this warrants that this verb will not raise the usecount of y or any of its contents even if they are passed through to the result.
#define VF2WILLOPEN1PROP       ((I)(((I)1)<<VF2WILLOPEN1PROPX))
// next flag must be same as JTWILLBEOPENED
#define VF2WILLOPEN1X      4   // This verb will open y as its first act, or will discard y.  No boxed contents in y can appear in the result (they may be virtual).  Monad case only.  This becomes the WILLBEOPENED flag in jt
#define VF2WILLOPEN1       ((I)(((I)1)<<VF2WILLOPEN1X))
// must leave a gap for WILLBEOPENED in result.h
// 5-6 free
// next flag must be same as JTCOUNTITEMS
#define VF2USESITEMCOUNT1X 7   // This verb can make use of an item count stored in m.  Monad case only
#define VF2USESITEMCOUNT1  ((I)(((I)1)<<VF2USESITEMCOUNT1X))
// must leave a gap for COUNTITEMS in result.h
// next 3 flags must be spaced from VF2BOXATOP? to match spacing in ZZFLAGS
#define VF2ATOPOPEN1X     8   // This verb is one of  > @> &> &.>
#define VF2ATOPOPEN1     ((I)(((I)1)<<VF2ATOPOPEN1X))
#define VF2ATOPOPEN2WX    9   // This verb is one of  &> &.>
#define VF2ATOPOPEN2W     ((I)(((I)1)<<VF2ATOPOPEN2WX))
#define VF2ATOPOPEN2AX    10   // This verb is one of  &> &.>
#define VF2ATOPOPEN2A     ((I)(((I)1)<<VF2ATOPOPEN2AX))

#define VF2RANKATOP1X     11   // set if this verb starts out with rank loop and thus can be subsumed into a higher rank loop
#define VF2RANKATOP1     ((I)(((I)1)<<VF2RANKATOP1X)) 
#define VF2RANKATOP2X     12   // set if this verb starts out with an outer rank loop.  " @ & &. and not special-cased
#define VF2RANKATOP2     ((I)(((I)1)<<VF2RANKATOP2X))
#define VF2RANKONLY1X     13   // set if this verb is u"r, not special-cased (i. e. function points to rank processing).  The rank may be subsumed into a higher rank before we see arguments.
#define VF2RANKONLY1     ((I)(((I)1)<<VF2RANKONLY1X)) 
#define VF2RANKONLY2X     14
#define VF2RANKONLY2     ((I)(((I)1)<<VF2RANKONLY2X))
// Next 6 flags must be spaced so they can shift down to VF2WILLOPEN1PROP, WILLOPEN1, and COUNTITEMS1
#define VF2WILLOPEN2WPROPX  15   // If WILLBEOPENED is set in jt coming into this verb, it should be passed through to the execution of the verb producing y.  Dyadic case.  Cannot be set if WILLOPEN is set.
#define VF2WILLOPEN2WPROP     ((I)(((I)1)<<VF2WILLOPEN2WPROPX))
#define VF2WILLOPEN2WX      16   // This verb will open y as its first act  This becomes the WILLBEOPENED flag in jt
#define VF2WILLOPEN2W       ((I)(((I)1)<<VF2WILLOPEN2WX))
#define VF2WILLOPEN2APROPX  17   // If WILLBEOPENED is set in jt coming into this verb, it should be passed through to the execution of the verb producing x.  Dyadic case.  Cannot be set if WILLOPEN is set.
#define VF2WILLOPEN2APROP     ((I)(((I)1)<<VF2WILLOPEN2APROPX))
#define VF2WILLOPEN2AX      18   // This verb will open x as its first act.  This becomes the WILLBEOPENED flag in jt
#define VF2WILLOPEN2A       ((I)(((I)1)<<VF2WILLOPEN2AX))
#define VF2USESITEMCOUNT2WX 19   // This verb can make use of an item count stored in m.  This becomes the COUNTITEMS flag in jt
#define VF2USESITEMCOUNT2W  ((I)(((I)1)<<VF2USESITEMCOUNT2WX))
#define VF2IMPLOCX 20   // This verb is one of u. v.
#define VF2IMPLOC  ((I)(((I)1)<<VF2IMPLOCX))
#define VF2USESITEMCOUNT2AX 21   // This verb can make use of an item count stored in m.  This becomes the COUNTITEMS flag in jt
#define VF2USESITEMCOUNT2A  ((I)(((I)1)<<VF2USESITEMCOUNT2AX))
#define VF2CACHEABLEX 21   // In a nameref, indicates the nameref is cacheable
#define VF2CACHEABLE  ((I)(((I)1)<<VF2CACHEABLEX))
#define VF2PRIMX 22   // Set in primitive ACV
#define VF2PRIM  ((I)(((I)1)<<VF2PRIMX))
#define VF2NAMELESSX 23   // Indicates value should be stacked instead of nameref
#define VF2NAMELESS  ((I)(((I)1)<<VF2NAMELESSX))
#define VF2CACHEDX 24   // In a nameref, indicates the nameref is cached, i. e. cacheable and filled in
#define VF2CACHED  ((I)(((I)1)<<VF2CACHEDX))
#define VF2PSEUDONAMEX 25  // in a nameref, indicates the nameref is VXOP type, either with a locative or during debug
#define VF2PSEUDONAME  ((I)(((I)1)<<VF2PSEUDONAMEX))

// layout of primitive, in the primtbl.  It is a memory header (shape 0) followed by a V
typedef struct __attribute__((aligned(ABDY))) {I memhdr[AKXR(0)/SZI]; union { V primvb; I primint; UI8 primfl; } prim; } PRIM;  // two cachelines exactly in 64-bit

// Canned blocks
// NOTE: for fetching IDs we use the validitymask as a safe place to fetch 0s from.  We know that
// validitymask[15] will be 0 on any platform
#define NUMERIC0 ((C*)(validitymask+12))  // 0 0 0 0 for numeric fill
#define FUNCTYPE0 ((A)(validitymask+12))  // 0 0 0 0, which has a 0 in the AT field
#define FUNCID0 ((A)(validitymask-4*(!SY_64)))  // 0 in index [15] ([19] for 32-bit), which has a 0 in the id field of V
#define SYMVAL0 ((L*)(validitymask+12))  // 0 0, which has a 0 in the val field of L
#define AFLAG0 ((A)(validitymask+12))  // 0 0 0 0, which has a 0 in the flag field and type field of A
#define ANLEN0 ((A)(validitymask+12-4))  // x x x x 0 0, which has a 0 in the AN field
#define ZAPLOC0 ((A*)(validitymask+12))  // 0 used as a pointer to a null tpop-stack value
#define PSTK2NOTFINALASGN ((PSTK*)(validitymask+12)-2)  // 0 in position [2], signifying NOT final assignment (used for errors)
#define BREAK0 ((C*)(validitymask+12))  // 0 to indicate no ATTN requested
#define MEMSET00 ((C*)(validitymask+12))  // 4 words bytes of 0, for memset
#define MEMSET00LEN (4*SZI)  // length of MEMSET00
#define MEMSETFF ((C*)(validitymask+8))  // 2 words of FF, for memset (only 2 in 32-bit systems)
#define MEMSETFFLEN (2*SZI)  // length of MEMSETFF
#define MEMSET01 ((C*)(iotavec-IOTAVECBEGIN+1))  // 1 byte of 0x01, for memset


// parser stack - should be a qword for fast copying
typedef struct {
  // Because the parse decode looks mostly at pt, make that the first thing so that it is always aligned to the beginning
  // of whatever block is used to copy one stack element to another.
 UI4 pt;  // parser type: code for one of the 9 variants recognized.
 S filler;
 US t;  // token number for this block - 16 bits of token.  After assignment, set to -1 if final assignment
 A a;  // pointer to block
} PSTK;

// stack frame used by the parser.  There are two stacks in a stack block: the normal execution stack
// which grows down from stkend1; an original-info stack that grows up from stkbgn.  stkbgn[-1] has the original info.
 typedef struct{
  PSTK* parserstkbgn;     // [0]:&start of parser stack  [-1]: address of words
  PSTK* parserstkend1;    // [0}&end+1 of parser stack   [-1]: number of words
  US parseroridetok;  // inited to -1; set to the failing token number+1 to override looking at the exec stack. 0 for no error-line flag.  This is done when pee is detected
                     // or preemptively for calls to syrd which can fail (kludge)
  C filler[SZI-sizeof(US)];
  A sf;   // $: stack in the parser (other users of $: have their own stacks) MUST BE LAST because it is part of a block stacked by unquote
 } PFRAME;  // these are stacked en bloc

// input/result for fmtlong
struct fmtbuf {
 C *buf;   // location of the MSD
 C *fbuf;   // workarea, ndig long, to hold decimal rep of fractional exponent
 I ndig;  // number of formatted digits (on input, max# allowed)
 I dp;  // (result) location of decimal point: to the left of digit dp
};

typedef struct {
  C*   sev;          /* comparison: sparse element value ptr            */
  I    si;           /* comparison: sparse current cell index           */
  I*   stv;          /* comparison: sparse element item indices         */
  I    swf;          /* comparison: sparse wf value                     */
  I    sxc;          /* comparison: sparse aii(x)                       */
  C*   sxv;          /* comparison: sparse AV(x)                        */
  I    syc;          /* comparison: sparse aii(y) or AS(y)[1]         */
  I*   syv;          /* comparison: sparse AV(y)                        */
 } SORTSP;   // sparse extension for sortblok

typedef struct {
  CMP  f;             /* comparison function in sort                     */
  struct JTTstruct * jt;           // jt, including the DESCEND flag
  I    n;            /* comparison: number of atoms in each item        */
  I    k;            /* comparison: byte size of each item              */
  C*   v;            /* comparison: beginning of data area              */
  SORTSP *sp;  // pointer to extension for sparse arrays
 } SORT;

// info for a fold
 struct foldstatus {
  I exestats[3]; // #times v has started, #times u has started, # values added to result
  I4 zstatus;   // nonzero if Z: was applied, with bit flags 0-4 = z: codes _3..1: fold limit; abort; abort iteration; quiet iteration; halt after current
 };  // fold status shared between F: and Z:

